diff --git a/Cargo.lock b/Cargo.lock
index f13ccecd9e29def568afc4ffb82397ee86fe0dd9..a2efd4fcf26459b4876f8a015131820b049fbaed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -18,6 +18,68 @@ version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046"
 
+[[package]]
+name = "accesskit"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "704d532b1cd3d912bb37499c55a81ac748cc1afa737eedd100ba441acdd47d38"
+
+[[package]]
+name = "accesskit_consumer"
+version = "0.14.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "48ba8b23cfca3944012ee2e5c71c02077a400e034c720eed6bd927cb6b4d1fd9"
+dependencies = [
+ "accesskit",
+]
+
+[[package]]
+name = "accesskit_macos"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58d062544d6cc36f4213323b7cb3a0d74ddff4b0d2311ab5e7596f4278bb2cc9"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "objc2",
+ "once_cell",
+]
+
+[[package]]
+name = "accesskit_windows"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaf5b3c3828397ee832ba4a72fb1a4ace10f781e31885f774cbd531014059115"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "arrayvec",
+ "once_cell",
+ "paste",
+ "windows 0.44.0",
+]
+
+[[package]]
+name = "accesskit_winit"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbcb615217efc79c4bed3094c4ca76c4bc554751d1da16f3ed4ba0459b1e8f31"
+dependencies = [
+ "accesskit",
+ "accesskit_macos",
+ "accesskit_windows",
+ "winit",
+]
+
+[[package]]
+name = "addr2line"
+version = "0.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
+dependencies = [
+ "gimli",
+]
+
 [[package]]
 name = "adler"
 version = "1.0.2"
@@ -46,14 +108,14 @@ dependencies = [
 
 [[package]]
 name = "alsa"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5915f52fe2cf65e83924d037b6c5290b7cee097c6b5c8700746e6168a343fd6b"
+checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44"
 dependencies = [
  "alsa-sys",
  "bitflags",
  "libc",
- "nix 0.23.2",
+ "nix 0.24.3",
 ]
 
 [[package]]
@@ -67,23 +129,35 @@ dependencies = [
 ]
 
 [[package]]
-name = "android_log-sys"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e"
-
-[[package]]
-name = "android_logger"
-version = "0.11.3"
+name = "android-activity"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8619b80c242aa7bd638b5c7ddd952addeecb71f69c75e33f1d47b2804f8f883a"
+checksum = "7c77a0045eda8b888c76ea473c2b0515ba6f471d318f8927c5c72240937035a6"
 dependencies = [
- "android_log-sys",
- "env_logger",
+ "android-properties",
+ "bitflags",
+ "cc",
+ "jni-sys",
+ "libc",
  "log",
- "once_cell",
+ "ndk",
+ "ndk-context",
+ "ndk-sys",
+ "num_enum",
 ]
 
+[[package]]
+name = "android-properties"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04"
+
+[[package]]
+name = "android_log-sys"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e"
+
 [[package]]
 name = "android_system_properties"
 version = "0.1.5"
@@ -129,7 +203,7 @@ version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
 dependencies = [
- "concurrent-queue 2.0.0",
+ "concurrent-queue",
  "event-listener",
  "futures-core",
 ]
@@ -142,7 +216,7 @@ checksum = "17adb73da160dfb475c183343c8cccd80721ea5a605d3eb57125f0a7b7a92d0b"
 dependencies = [
  "async-lock",
  "async-task",
- "concurrent-queue 2.0.0",
+ "concurrent-queue",
  "fastrand",
  "futures-lite",
  "slab",
@@ -171,10 +245,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
-name = "base-x"
-version = "0.2.11"
+name = "backtrace"
+version = "0.3.67"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cbbc9d0964165b47557570cce6c952866c2678457aca742aafc9fb771d30270"
+checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca"
+dependencies = [
+ "addr2line",
+ "cc",
+ "cfg-if",
+ "libc",
+ "miniz_oxide",
+ "object",
+ "rustc-demangle",
+]
 
 [[package]]
 name = "base64"
@@ -184,18 +267,30 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 
 [[package]]
 name = "bevy"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dae99b246505811f5bc19d2de1e406ec5d2816b421d58fa223779eb576f472c9"
+checksum = "b93f906133305915d63f04108e6873c1b93a6605fe374b8f3391f6bda093e396"
 dependencies = [
  "bevy_internal",
 ]
 
+[[package]]
+name = "bevy_a11y"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "037c4063f7dac1a5d596eb47f40782a04ca5838dc4274dbbadc90eb81efe5169"
+dependencies = [
+ "accesskit",
+ "bevy_app",
+ "bevy_derive",
+ "bevy_ecs",
+]
+
 [[package]]
 name = "bevy_animation"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d43b8073f299eb60ce9e1d60fa293b348590dd57aca8321d6859d9e7aa57d2da"
+checksum = "d0dc19f21846ebf8ba4d96617c2517b5119038774aa5dbbaf1bff122332b359c"
 dependencies = [
  "bevy_app",
  "bevy_asset",
@@ -211,9 +306,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_app"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "536e4d0018347478545ed8b6cb6e57b9279ee984868e81b7c0e78e0fb3222e42"
+checksum = "01db46963eb9486f7884121527ec69751d0e448f9e1d5329e80ea3424118a31a"
 dependencies = [
  "bevy_derive",
  "bevy_ecs",
@@ -226,9 +321,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_asset"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6db1bb550168304df69c867c09125e1aae7ff51cf21575396e1598bf293442c4"
+checksum = "98609b4b0694a23bde0628aed626644967991f167aad9db2afb68dacb0017540"
 dependencies = [
  "anyhow",
  "bevy_app",
@@ -238,11 +333,11 @@ dependencies = [
  "bevy_reflect",
  "bevy_tasks",
  "bevy_utils",
+ "bevy_winit",
  "crossbeam-channel",
  "downcast-rs",
  "fastrand",
  "js-sys",
- "ndk-glue",
  "notify",
  "parking_lot",
  "serde",
@@ -254,25 +349,28 @@ dependencies = [
 
 [[package]]
 name = "bevy_audio"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "29a05efc6c23bef37520e44029943c65b7e8a4fe4f5e54cb3f96e63ce0b3d361"
+checksum = "42b9f9b87b0d094268ce52bb75ff346ae0054573f7acc5d66bf032e2c88f748d"
 dependencies = [
  "anyhow",
  "bevy_app",
  "bevy_asset",
  "bevy_ecs",
+ "bevy_math",
  "bevy_reflect",
+ "bevy_transform",
  "bevy_utils",
+ "oboe",
  "parking_lot",
  "rodio",
 ]
 
 [[package]]
 name = "bevy_core"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96299aceb3c8362cb4aa39ff81c7ef758a5f4e768d16b5046a91628eff114ac0"
+checksum = "0ee53d7b4691b57207d72e996992c995a53f3e8d21ca7151ca3956d9ce7d232e"
 dependencies = [
  "bevy_app",
  "bevy_ecs",
@@ -285,9 +383,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_core_pipeline"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc128a9860aadf16fb343ae427f2768986fd91dce64d945455acda9759c48014"
+checksum = "093ae5ced77251602ad6e43521e2acc1a5570bf85b80f232f1a7fdd43b50f8d8"
 dependencies = [
  "bevy_app",
  "bevy_asset",
@@ -305,20 +403,20 @@ dependencies = [
 
 [[package]]
 name = "bevy_derive"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7baf73c58d41c353c6fd08e6764a2e7420c9f19e8227b391c50981db6d0282a6"
+checksum = "dff0add5ab4a6b2b7e86e18f9043bb48b6386faa3b56abaa0ed97a3d669a1992"
 dependencies = [
  "bevy_macro_utils",
- "quote 1.0.23",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
 [[package]]
 name = "bevy_diagnostic"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63bf96ec7980fa25b77ff6c72dfafada477936c0dab76c1edf6c028c0e5fe0e4"
+checksum = "64c778422643b0adee9e82abbd07e1e906eb9947c274a9b18e0f7fbf137d4c34"
 dependencies = [
  "bevy_app",
  "bevy_core",
@@ -326,13 +424,14 @@ dependencies = [
  "bevy_log",
  "bevy_time",
  "bevy_utils",
+ "sysinfo",
 ]
 
 [[package]]
 name = "bevy_ecs"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d4c071d7c6bc9801253485e05d0c257284150de755391902746837ba21c0cf74"
+checksum = "bed2f74687ccf13046c0f8e3b00dc61d7e656877b4a1380cf04635bb74d8e586"
 dependencies = [
  "async-channel",
  "bevy_ecs_macros",
@@ -343,28 +442,28 @@ dependencies = [
  "downcast-rs",
  "event-listener",
  "fixedbitset",
- "fxhash",
+ "rustc-hash",
  "serde",
  "thread_local",
 ]
 
 [[package]]
 name = "bevy_ecs_macros"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c15bd45438eeb681ad74f2d205bb07a5699f98f9524462a30ec764afab2742ce"
+checksum = "a97fd126a0db7b30fb1833614b3a657b44ac88485741c33b2780e25de0f96d78"
 dependencies = [
  "bevy_macro_utils",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
 [[package]]
 name = "bevy_encase_derive"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "962b6bb0d30e92ec2e6c29837acce9e55b920733a634e7c3c5fd5a514bea7a24"
+checksum = "c086ebdc1f5522787d63772943277cc74a279445fb65db4d58c2c5330654648e"
 dependencies = [
  "bevy_macro_utils",
  "encase_derive_impl",
@@ -372,9 +471,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_gilrs"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4af552dad82f854b2fae24f36a389fd8ee99d65fe86ae876e854e70d53ff16d9"
+checksum = "3f32eb07e8c9ea4be7195ccec10d8f9ad70200f3ae2e13adc4b84df9f50bb1c6"
 dependencies = [
  "bevy_app",
  "bevy_ecs",
@@ -385,9 +484,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_gltf"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e853e346ba412354e02292c7aa5b9a9dccdfa748e273b1b7ebf8f6a172f89712"
+checksum = "2707632208617c3660ea7a1d2ef2ccc84b59f217c2f01a1d0abe81db4ae7bbde"
 dependencies = [
  "anyhow",
  "base64",
@@ -414,9 +513,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_hierarchy"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8dd6d50c48c6e1bcb5e08a768b765323292bb3bf3a439b992754c57ffb85b23a"
+checksum = "9d04099865a13d1fd8bf3c044a80148cb3d23bfe8c3d5f082dda2ce091d85532"
 dependencies = [
  "bevy_app",
  "bevy_core",
@@ -429,9 +528,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_input"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3378b5171284f4c4c0e8307081718a9fe458f846444616bd82d69110dcabca51"
+checksum = "a15d40aa636bb656967ac16ca36066ab7a7bb9179e1b0390c5705e54208e8fd7"
 dependencies = [
  "bevy_app",
  "bevy_ecs",
@@ -443,10 +542,11 @@ dependencies = [
 
 [[package]]
 name = "bevy_internal"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c46014b7e885b1311de06b6039e448454a4db55b8d35464798ba88faa186e11"
+checksum = "862b11931c5874cb00778ffb715fc526ee49e52a493d3bcf50e8010f301858b3"
 dependencies = [
+ "bevy_a11y",
  "bevy_animation",
  "bevy_app",
  "bevy_asset",
@@ -476,14 +576,13 @@ dependencies = [
  "bevy_utils",
  "bevy_window",
  "bevy_winit",
- "ndk-glue",
 ]
 
 [[package]]
 name = "bevy_log"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c480bac54cf4ae76edc3ae9ae3fa7c5e1b385e7f2111ef5ec3fd00cf3a7998b"
+checksum = "25980c90ceaad34d09a53291e72ca56fcc754a974cd4654fffcf5b68b283b7a7"
 dependencies = [
  "android_log-sys",
  "bevy_app",
@@ -497,20 +596,20 @@ dependencies = [
 
 [[package]]
 name = "bevy_macro_utils"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "022bb69196deeea691b6997414af85bbd7f2b34a8914c4aa7a7ff4dfa44f7677"
+checksum = "5b2fee53b2497cdc3bffff2ddf52afa751242424a5fd0d51d227d4dab081d0d9"
 dependencies = [
- "quote 1.0.23",
+ "quote 1.0.26",
  "syn 1.0.107",
- "toml",
+ "toml_edit",
 ]
 
 [[package]]
 name = "bevy_math"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d434c77ab766c806ed9062ef8a7285b3b02b47df51f188d4496199c3ac062eaf"
+checksum = "da6a1109d06fe947990db032e719e162414cf9bf7a478dcc52742f1c7136c42a"
 dependencies = [
  "glam",
  "serde",
@@ -518,18 +617,18 @@ dependencies = [
 
 [[package]]
 name = "bevy_mikktspace"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbfb5908d33fd613069be516180b8f138aaaf6e41c36b1fd98c6c29c00c24a13"
+checksum = "39106bc2ee21fce9496d2e15e0ba7925dff63e3eae10f7c1fc0094b56ad9f2bb"
 dependencies = [
  "glam",
 ]
 
 [[package]]
 name = "bevy_pbr"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "310b1f260a475d81445623e138e1b7245759a42310bc1f84b550a3f4ff8763bf"
+checksum = "4f507cef55812aa70c2ec2b30fb996eb285fa7497d974cf03f76ec49c77fbe27"
 dependencies = [
  "bevy_app",
  "bevy_asset",
@@ -549,15 +648,15 @@ dependencies = [
 
 [[package]]
 name = "bevy_ptr"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ec44f7655039546bc5d34d98de877083473f3e9b2b81d560c528d6d74d3eff4"
+checksum = "0c4b88451d4c5a353bff67dbaa937b6886efd26ae114769c17f2b35099c7a4de"
 
 [[package]]
 name = "bevy_reflect"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6deae303a7f69dc243b2fa35b5e193cc920229f448942080c8eb2dbd9de6d37a"
+checksum = "9fc3979471890e336f3ba87961ef3ecd45c331cf2cb2f582c885e541af228b48"
 dependencies = [
  "bevy_math",
  "bevy_ptr",
@@ -575,25 +674,26 @@ dependencies = [
 
 [[package]]
 name = "bevy_reflect_derive"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a2bf4cb9cd5acb4193f890f36cb63679f1502e2de025e66a63b194b8b133d018"
+checksum = "2bc7ea7c9bc2c531eb29ba5619976613d6680453ff5dd4a7fcd08848e8bec5ad"
 dependencies = [
  "bevy_macro_utils",
  "bit-set",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
  "uuid",
 ]
 
 [[package]]
 name = "bevy_render"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e3282a8f8779d2aced93207fbed73f740937c6c2bd27bd84f0799b081c7fca5"
+checksum = "ee1e126226f0a4d439bf82fe07c1104f894a6a365888e3eba7356f9647e77a83"
 dependencies = [
  "anyhow",
+ "async-channel",
  "bevy_app",
  "bevy_asset",
  "bevy_core",
@@ -606,6 +706,7 @@ dependencies = [
  "bevy_mikktspace",
  "bevy_reflect",
  "bevy_render_macros",
+ "bevy_tasks",
  "bevy_time",
  "bevy_transform",
  "bevy_utils",
@@ -615,37 +716,39 @@ dependencies = [
  "downcast-rs",
  "encase",
  "futures-lite",
- "hex",
  "hexasphere",
  "image",
+ "ktx2",
  "naga",
  "once_cell",
  "parking_lot",
  "regex",
+ "ruzstd",
  "serde",
  "smallvec",
  "thiserror",
  "thread_local",
  "wgpu",
+ "wgpu-hal",
 ]
 
 [[package]]
 name = "bevy_render_macros"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7acae697776ac05bea523e1725cf2660c91c53abe72c66782ea1e1b9eedb572"
+checksum = "652f8c4d9577c6e6a8b3dfd8a4ce331e8b6ecdbb99636a4b2701dec50104d6bc"
 dependencies = [
  "bevy_macro_utils",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
 [[package]]
 name = "bevy_scene"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea9c66a628c833d53bae54fe94cbc0d3f12c29e9d2e6c3f2356d45ad57db0c8c"
+checksum = "1de59637d27726251091120ce6f63917328ffd60aaccbda4d65a615873aff631"
 dependencies = [
  "anyhow",
  "bevy_app",
@@ -665,9 +768,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_sprite"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ec01c7db7f698d95bcb70708527c3ae6bcdc78fc247abe74f935cae8f0a1145"
+checksum = "c110358fe3651a5796fd1c07989635680738f5b5c7e9b8a463dd50d12bb78410"
 dependencies = [
  "bevy_app",
  "bevy_asset",
@@ -690,14 +793,14 @@ dependencies = [
 
 [[package]]
 name = "bevy_tasks"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "680b16b53df9c9f24681dd95f4d772d83760bd19adf8bca00f358a3aad997853"
+checksum = "3de86364316e151aeb0897eaaa917c3ad5ee5ef1471a939023cf7f2d5ab76955"
 dependencies = [
  "async-channel",
  "async-executor",
  "async-task",
- "concurrent-queue 1.2.4",
+ "concurrent-queue",
  "futures-lite",
  "once_cell",
  "wasm-bindgen-futures",
@@ -705,9 +808,9 @@ dependencies = [
 
 [[package]]
 name = "bevy_text"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60c74c1bdaabde7db28f6728aa13bc7b1d744a2201b2bbfd83d2224404c57f5c"
+checksum = "995188f59dc06da3fc951e1f58a105cde2c817d5330ae67ddc0a140f46482f6b"
 dependencies = [
  "ab_glyph",
  "anyhow",
@@ -728,22 +831,23 @@ dependencies = [
 
 [[package]]
 name = "bevy_time"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a5c38a6d3ea929c7f81e6adf5a6c62cf7e8c40f5106c2174d6057e9d8ea624d"
+checksum = "d3edbd605df1bced312eb9888d6be3d5a5fcac3d4140038bbe3233d218399eef"
 dependencies = [
  "bevy_app",
  "bevy_ecs",
  "bevy_reflect",
  "bevy_utils",
  "crossbeam-channel",
+ "thiserror",
 ]
 
 [[package]]
 name = "bevy_transform"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba13c57a040b89767191a6f6d720a635b7792793628bfa41a9e38b7026484aec"
+checksum = "24383dfb97d8a14b17721ecfdf58556eff5ea9a4b2a3d91accf2b472783880b0"
 dependencies = [
  "bevy_app",
  "bevy_ecs",
@@ -754,10 +858,11 @@ dependencies = [
 
 [[package]]
 name = "bevy_ui"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60e82ace6156f11fcdf2319102ff8fb8367b82d1e32b7d05d387a1963602f965"
+checksum = "cb597aeed4e1bf5e6913879c3e22a7d50a843b822a7f71a4a80ebdfdf79e68d4"
 dependencies = [
+ "bevy_a11y",
  "bevy_app",
  "bevy_asset",
  "bevy_core_pipeline",
@@ -783,23 +888,37 @@ dependencies = [
 
 [[package]]
 name = "bevy_utils"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16750aae52cd35bd7b60eb61cee883420b250e11b4a290b8d44b2b2941795739"
+checksum = "0a88ebbca55d360d72e9fe78df0d22e25cd419933c9559e79dae2757f7c4d066"
 dependencies = [
  "ahash",
+ "bevy_utils_proc_macros",
  "getrandom",
  "hashbrown",
  "instant",
+ "petgraph",
+ "thiserror",
  "tracing",
  "uuid",
 ]
 
+[[package]]
+name = "bevy_utils_proc_macros"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "630b92e32fa5cd7917c7d4fdbf63a90af958b01e096239f71bc4f8f3cf40c0d2"
+dependencies = [
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
+ "syn 1.0.107",
+]
+
 [[package]]
 name = "bevy_window"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0a44d3f3bd54a2261f4f57f614bf7bccc8d2832761493c0cd7dab81d98cc151e"
+checksum = "ad31234754268fbe12050290b0496e2296252a16995a38f94bfb9680a4f09fda"
 dependencies = [
  "bevy_app",
  "bevy_ecs",
@@ -807,24 +926,29 @@ dependencies = [
  "bevy_math",
  "bevy_reflect",
  "bevy_utils",
- "raw-window-handle 0.5.0",
+ "raw-window-handle",
 ]
 
 [[package]]
 name = "bevy_winit"
-version = "0.9.1"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c7b7e647ecd0b3577468da37767dcdd7c26ca9f80da0060b2ec4c77336b6d2e1"
+checksum = "cf17bd6330f7e633b7c56754c776511a8f52cde4bf54c0278f34d7527548f253"
 dependencies = [
+ "accesskit_winit",
  "approx",
+ "bevy_a11y",
  "bevy_app",
+ "bevy_derive",
  "bevy_ecs",
+ "bevy_hierarchy",
  "bevy_input",
  "bevy_math",
  "bevy_utils",
  "bevy_window",
  "crossbeam-channel",
- "raw-window-handle 0.5.0",
+ "once_cell",
+ "raw-window-handle",
  "wasm-bindgen",
  "web-sys",
  "winit",
@@ -842,8 +966,8 @@ dependencies = [
  "lazy_static",
  "lazycell",
  "peeking_take_while",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "regex",
  "rustc-hash",
  "shlex",
@@ -877,6 +1001,25 @@ version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
 
+[[package]]
+name = "block-sys"
+version = "0.1.0-beta.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146"
+dependencies = [
+ "objc-sys",
+]
+
+[[package]]
+name = "block2"
+version = "0.2.0-alpha.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42"
+dependencies = [
+ "block-sys",
+ "objc2-encode",
+]
+
 [[package]]
 name = "bumpalo"
 version = "3.11.1"
@@ -898,8 +1041,8 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5fe233b960f12f8007e3db2d136e3cb1c291bfd7396e384ee76025fc1a3932b4"
 dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
@@ -915,12 +1058,6 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
 
-[[package]]
-name = "cache-padded"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c"
-
 [[package]]
 name = "cc"
 version = "1.0.78"
@@ -968,37 +1105,6 @@ dependencies = [
  "libloading",
 ]
 
-[[package]]
-name = "cocoa"
-version = "0.24.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a"
-dependencies = [
- "bitflags",
- "block",
- "cocoa-foundation",
- "core-foundation",
- "core-graphics",
- "foreign-types",
- "libc",
- "objc",
-]
-
-[[package]]
-name = "cocoa-foundation"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
-dependencies = [
- "bitflags",
- "block",
- "core-foundation",
- "core-graphics-types",
- "foreign-types",
- "libc",
- "objc",
-]
-
 [[package]]
 name = "codespan-reporting"
 version = "0.11.1"
@@ -1015,6 +1121,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b"
 
+[[package]]
+name = "com-rs"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf43edc576402991846b093a7ca18a3477e0ef9c588cde84964b5d3e43016642"
+
 [[package]]
 name = "combine"
 version = "4.6.6"
@@ -1025,15 +1137,6 @@ dependencies = [
  "memchr",
 ]
 
-[[package]]
-name = "concurrent-queue"
-version = "1.2.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af4780a44ab5696ea9e28294517f1fffb421a83a25af521333c838635509db9c"
-dependencies = [
- "cache-padded",
-]
-
 [[package]]
 name = "concurrent-queue"
 version = "2.0.0"
@@ -1065,10 +1168,16 @@ version = "0.9.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
 dependencies = [
- "core-foundation-sys",
+ "core-foundation-sys 0.8.3",
  "libc",
 ]
 
+[[package]]
+name = "core-foundation-sys"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
+
 [[package]]
 name = "core-foundation-sys"
 version = "0.8.3"
@@ -1102,11 +1211,12 @@ dependencies = [
 
 [[package]]
 name = "coreaudio-rs"
-version = "0.10.0"
+version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88"
+checksum = "cb17e2d1795b1996419648915df94bc7103c28f7b48062d7acf4652fc371b2ff"
 dependencies = [
  "bitflags",
+ "core-foundation-sys 0.6.2",
  "coreaudio-sys",
 ]
 
@@ -1121,27 +1231,27 @@ dependencies = [
 
 [[package]]
 name = "cpal"
-version = "0.14.2"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f342c1b63e185e9953584ff2199726bf53850d96610a310e3aca09e9405a2d0b"
+checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c"
 dependencies = [
  "alsa",
- "core-foundation-sys",
+ "core-foundation-sys 0.8.3",
  "coreaudio-rs",
- "jni",
+ "dasp_sample",
+ "jni 0.19.0",
  "js-sys",
  "libc",
- "mach",
- "ndk 0.7.0",
+ "mach2",
+ "ndk",
  "ndk-context",
  "oboe",
  "once_cell",
  "parking_lot",
- "stdweb",
- "thiserror",
  "wasm-bindgen",
+ "wasm-bindgen-futures",
  "web-sys",
- "windows 0.37.0",
+ "windows 0.46.0",
 ]
 
 [[package]]
@@ -1180,9 +1290,9 @@ checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
 
 [[package]]
 name = "d3d12"
-version = "0.5.0"
+version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "827914e1f53b1e0e025ecd3d967a7836b7bcb54520f90e21ef8df7b4d88a2759"
+checksum = "d8f0de2f5a8e7bd4a9eec0e3c781992a4ce1724f68aec7d7a3715344de8b39da"
 dependencies = [
  "bitflags",
  "libloading",
@@ -1195,18 +1305,8 @@ version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fcfbcb0c5961907597a7d1148e3af036268f2b773886b8bb3eeb1e1281d3d3d6"
 dependencies = [
- "darling_core 0.9.0",
- "darling_macro 0.9.0",
-]
-
-[[package]]
-name = "darling"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
-dependencies = [
- "darling_core 0.13.4",
- "darling_macro 0.13.4",
+ "darling_core",
+ "darling_macro",
 ]
 
 [[package]]
@@ -1219,45 +1319,26 @@ dependencies = [
  "ident_case",
  "proc-macro2 0.4.30",
  "quote 0.6.13",
- "strsim 0.7.0",
+ "strsim",
  "syn 0.15.44",
 ]
 
-[[package]]
-name = "darling_core"
-version = "0.13.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
-dependencies = [
- "fnv",
- "ident_case",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
- "strsim 0.10.0",
- "syn 1.0.107",
-]
-
 [[package]]
 name = "darling_macro"
 version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c6d8dac1c6f1d29a41c4712b4400f878cb4fcc4c7628f298dd75038e024998d1"
 dependencies = [
- "darling_core 0.9.0",
+ "darling_core",
  "quote 0.6.13",
  "syn 0.15.44",
 ]
 
 [[package]]
-name = "darling_macro"
-version = "0.13.4"
+name = "dasp_sample"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
-dependencies = [
- "darling_core 0.13.4",
- "quote 1.0.23",
- "syn 1.0.107",
-]
+checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
 
 [[package]]
 name = "derive_builder"
@@ -1265,7 +1346,7 @@ version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3ac53fa6a3cda160df823a9346442525dcaf1e171999a1cf23e67067e4fd64d4"
 dependencies = [
- "darling 0.9.0",
+ "darling",
  "derive_builder_core",
  "proc-macro2 0.4.30",
  "quote 0.6.13",
@@ -1278,18 +1359,12 @@ version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0288a23da9333c246bb18c143426074a6ae96747995c5819d2947b64cd942b37"
 dependencies = [
- "darling 0.9.0",
+ "darling",
  "proc-macro2 0.4.30",
  "quote 0.6.13",
  "syn 0.15.44",
 ]
 
-[[package]]
-name = "discard"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0"
-
 [[package]]
 name = "dispatch"
 version = "0.2.0"
@@ -1304,9 +1379,9 @@ checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
 
 [[package]]
 name = "encase"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "48ec50086547d597b5c871a78399ec04a14828a6a5c445a61ed4687c540edec6"
+checksum = "e6591f13a63571c4821802eb5b10fd1155b1290bce87086440003841c8c3909b"
 dependencies = [
  "const_panic",
  "encase_derive",
@@ -1316,34 +1391,24 @@ dependencies = [
 
 [[package]]
 name = "encase_derive"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dda93e9714c7683c474f49a461a2ae329471d2bda43c4302d41c6d8339579e92"
+checksum = "4f1da6deed1f8b6f5909616ffa695f63a5de54d6a0f084fa715c70c8ed3abac9"
 dependencies = [
  "encase_derive_impl",
 ]
 
 [[package]]
 name = "encase_derive_impl"
-version = "0.4.1"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec27b639e942eb0297513b81cc6d87c50f6c77dc8c37af00a39ed5db3b9657ee"
+checksum = "ae489d58959f3c4cdd1250866a05acfb341469affe4fced71aff3ba228be1693"
 dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
-[[package]]
-name = "env_logger"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
-dependencies = [
- "log",
- "regex",
-]
-
 [[package]]
 name = "erased-serde"
 version = "0.3.24"
@@ -1385,7 +1450,7 @@ checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "windows-sys 0.42.0",
 ]
 
@@ -1517,11 +1582,17 @@ dependencies = [
  "windows 0.43.0",
 ]
 
+[[package]]
+name = "gimli"
+version = "0.27.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
+
 [[package]]
 name = "glam"
-version = "0.22.0"
+version = "0.23.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12f597d56c1bd55a811a1be189459e8fad2bbc272616375602443bdfb37fa774"
+checksum = "8e4afd9ad95555081e109fe1d21f2a30c691b5f0919c67dfa690a2e1eb6bd51c"
 dependencies = [
  "bytemuck",
  "serde",
@@ -1535,9 +1606,9 @@ checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
 
 [[package]]
 name = "glow"
-version = "0.11.2"
+version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919"
+checksum = "4e007a07a24de5ecae94160f141029e9a347282cfe25d1d58d85d845cf3130f1"
 dependencies = [
  "js-sys",
  "slotmap",
@@ -1563,8 +1634,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bdd53d6e284bb2bf02a6926e4cc4984978c1990914d6cd9deae4e31cf37cd113"
 dependencies = [
  "inflections",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
@@ -1610,6 +1681,19 @@ dependencies = [
  "bitflags",
 ]
 
+[[package]]
+name = "gpu-allocator"
+version = "0.22.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce95f9e2e11c2c6fadfce42b5af60005db06576f231f5c92550fdded43c423e8"
+dependencies = [
+ "backtrace",
+ "log",
+ "thiserror",
+ "winapi",
+ "windows 0.44.0",
+]
+
 [[package]]
 name = "gpu-descriptor"
 version = "0.2.3"
@@ -1641,46 +1725,35 @@ dependencies = [
 ]
 
 [[package]]
-name = "hash32"
-version = "0.2.1"
+name = "hashbrown"
+version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 dependencies = [
- "byteorder",
+ "ahash",
+ "serde",
 ]
 
 [[package]]
-name = "hash32-derive"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59d2aba832b60be25c1b169146b27c64115470981b128ed84c8db18c1b03c6ff"
-dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
- "syn 1.0.107",
-]
-
-[[package]]
-name = "hashbrown"
-version = "0.12.3"
+name = "hassle-rs"
+version = "0.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+checksum = "90601c6189668c7345fc53842cb3f3a3d872203d523be1b3cb44a36a3e62fb85"
 dependencies = [
- "ahash",
- "serde",
+ "bitflags",
+ "com-rs",
+ "libc",
+ "libloading",
+ "thiserror",
+ "widestring",
+ "winapi",
 ]
 
-[[package]]
-name = "hex"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
-
 [[package]]
 name = "hexasphere"
-version = "8.0.0"
+version = "8.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "619ce654558681d7d0a7809e1b20249c7032ff13ee6baa7bb7ff64f7f28a906a"
+checksum = "bd41d443f978bfa380a6dad58b62a08c43bcb960631f13e9d015b911eaf73588"
 dependencies = [
  "glam",
  "once_cell",
@@ -1767,7 +1840,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7789f7f3c9686f96164f5109d69152de759e76e284f736bd57661c6df5091919"
 dependencies = [
- "core-foundation-sys",
+ "core-foundation-sys 0.8.3",
  "mach",
 ]
 
@@ -1791,6 +1864,20 @@ dependencies = [
  "walkdir",
 ]
 
+[[package]]
+name = "jni"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
+dependencies = [
+ "cesu8",
+ "combine",
+ "jni-sys",
+ "log",
+ "thiserror",
+ "walkdir",
+]
+
 [[package]]
 name = "jni-sys"
 version = "0.3.0"
@@ -1808,9 +1895,9 @@ dependencies = [
 
 [[package]]
 name = "js-sys"
-version = "0.3.60"
+version = "0.3.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -1846,6 +1933,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "ktx2"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87d65e08a9ec02e409d27a0139eaa6b9756b4d81fe7cde71f6941a83730ce838"
+dependencies = [
+ "bitflags",
+]
+
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
@@ -1858,16 +1954,6 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
-[[package]]
-name = "ldtk_rust"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e6ec9d145e9e4265fc8d473114353c07ab84a21ea1e1ad7c86ba7fc6337aebe"
-dependencies = [
- "serde",
- "serde_json",
-]
-
 [[package]]
 name = "lewton"
 version = "0.10.2"
@@ -1933,6 +2019,15 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "mach2"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
+dependencies = [
+ "libc",
+]
+
 [[package]]
 name = "malloc_buf"
 version = "0.0.6"
@@ -1957,15 +2052,6 @@ version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
 
-[[package]]
-name = "memoffset"
-version = "0.6.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
-dependencies = [
- "autocfg",
-]
-
 [[package]]
 name = "metal"
 version = "0.24.0"
@@ -1986,12 +2072,12 @@ version = "0.2.0"
 dependencies = [
  "anyhow",
  "bevy",
- "ldtk_rust",
  "log",
  "num-traits",
  "quadtree_rs",
  "serde",
  "serde_json",
+ "thiserror",
 ]
 
 [[package]]
@@ -2023,9 +2109,9 @@ dependencies = [
 
 [[package]]
 name = "naga"
-version = "0.10.0"
+version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "262d2840e72dbe250e8cf2f522d080988dfca624c4112c096238a4845f591707"
+checksum = "5eafe22a23b797c9bc227c6c896419b26b5bb88fa903417a3adaed08778850d5"
 dependencies = [
  "bit-set",
  "bitflags",
@@ -2043,19 +2129,6 @@ dependencies = [
  "unicode-xid 0.2.4",
 ]
 
-[[package]]
-name = "ndk"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2032c77e030ddee34a6787a64166008da93f6a352b629261d0fee232b8742dd4"
-dependencies = [
- "bitflags",
- "jni-sys",
- "ndk-sys 0.3.0",
- "num_enum",
- "thiserror",
-]
-
 [[package]]
 name = "ndk"
 version = "0.7.0"
@@ -2064,9 +2137,9 @@ checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
 dependencies = [
  "bitflags",
  "jni-sys",
- "ndk-sys 0.4.1+23.1.7779620",
+ "ndk-sys",
  "num_enum",
- "raw-window-handle 0.5.0",
+ "raw-window-handle",
  "thiserror",
 ]
 
@@ -2076,45 +2149,6 @@ version = "0.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
 
-[[package]]
-name = "ndk-glue"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f"
-dependencies = [
- "android_logger",
- "libc",
- "log",
- "ndk 0.7.0",
- "ndk-context",
- "ndk-macro",
- "ndk-sys 0.4.1+23.1.7779620",
- "once_cell",
- "parking_lot",
-]
-
-[[package]]
-name = "ndk-macro"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
-dependencies = [
- "darling 0.13.4",
- "proc-macro-crate",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
- "syn 1.0.107",
-]
-
-[[package]]
-name = "ndk-sys"
-version = "0.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6e5a6ae77c8ee183dcbbba6150e2e6b9f3f4196a7666c02a715a95692ec1fa97"
-dependencies = [
- "jni-sys",
-]
-
 [[package]]
 name = "ndk-sys"
 version = "0.4.1+23.1.7779620"
@@ -2126,15 +2160,13 @@ dependencies = [
 
 [[package]]
 name = "nix"
-version = "0.23.2"
+version = "0.24.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
+checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
 dependencies = [
  "bitflags",
- "cc",
  "cfg-if",
  "libc",
- "memoffset",
 ]
 
 [[package]]
@@ -2177,6 +2209,15 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "ntapi"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc"
+dependencies = [
+ "winapi",
+]
+
 [[package]]
 name = "nu-ansi-term"
 version = "0.46.0"
@@ -2228,8 +2269,8 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
 dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
@@ -2302,8 +2343,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
 dependencies = [
  "proc-macro-crate",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
@@ -2317,6 +2358,32 @@ dependencies = [
  "objc_exception",
 ]
 
+[[package]]
+name = "objc-sys"
+version = "0.2.0-beta.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7"
+
+[[package]]
+name = "objc2"
+version = "0.3.0-beta.3.patch-leaks.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e01640f9f2cb1220bbe80325e179e532cb3379ebcd1bf2279d703c19fe3a468"
+dependencies = [
+ "block2",
+ "objc-sys",
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "2.0.0-pre.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512"
+dependencies = [
+ "objc-sys",
+]
+
 [[package]]
 name = "objc_exception"
 version = "0.1.2"
@@ -2326,14 +2393,23 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "object"
+version = "0.30.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "oboe"
-version = "0.4.6"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "27f63c358b4fa0fbcfefd7c8be5cfc39c08ce2389f5325687e7762a48d30a5c1"
+checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0"
 dependencies = [
- "jni",
- "ndk 0.6.0",
+ "jni 0.20.0",
+ "ndk",
  "ndk-context",
  "num-derive",
  "num-traits",
@@ -2342,9 +2418,9 @@ dependencies = [
 
 [[package]]
 name = "oboe-sys"
-version = "0.4.5"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3370abb7372ed744232c12954d920d1a40f1c4686de9e79e800021ef492294bd"
+checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2"
 dependencies = [
  "cc",
 ]
@@ -2364,6 +2440,18 @@ version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
 
+[[package]]
+name = "orbclient"
+version = "0.3.44"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e9829e16c5e112e94efb5e2ad1fe17f8c1c99bb0fcdc8c65c44e935d904767d"
+dependencies = [
+ "cfg-if",
+ "redox_syscall 0.2.16",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "overload"
 version = "0.1.1"
@@ -2403,11 +2491,17 @@ checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.2.16",
  "smallvec",
  "windows-sys 0.42.0",
 ]
 
+[[package]]
+name = "paste"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
+
 [[package]]
 name = "peeking_take_while"
 version = "0.1.2"
@@ -2485,9 +2579,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.49"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57a8eca9f9c4ffde41714334dee777596264c7825420f521abc92b5b5deb63a5"
+checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
 dependencies = [
  "unicode-ident",
 ]
@@ -2519,11 +2613,11 @@ dependencies = [
 
 [[package]]
 name = "quote"
-version = "1.0.23"
+version = "1.0.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
 dependencies = [
- "proc-macro2 1.0.49",
+ "proc-macro2 1.0.56",
 ]
 
 [[package]]
@@ -2538,15 +2632,6 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "63e935c45e09cc6dcf00d2f0b2d630a58f4095320223d47fc68918722f0538b6"
 
-[[package]]
-name = "raw-window-handle"
-version = "0.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
-dependencies = [
- "cty",
-]
-
 [[package]]
 name = "raw-window-handle"
 version = "0.5.0"
@@ -2571,6 +2656,15 @@ dependencies = [
  "bitflags",
 ]
 
+[[package]]
+name = "redox_syscall"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+dependencies = [
+ "bitflags",
+]
+
 [[package]]
 name = "regex"
 version = "1.7.1"
@@ -2605,9 +2699,9 @@ checksum = "f1382d1f0a252c4bf97dc20d979a2fdd05b024acd7c2ed0f7595d7817666a157"
 
 [[package]]
 name = "rodio"
-version = "0.16.0"
+version = "0.17.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb10b653d5ec0e9411a2e7d46e2c7f4046fd87d35b9955bd73ba4108d69072b5"
+checksum = "bdf1d4dea18dff2e9eb6dca123724f8b60ef44ad74a9ad283cdfe025df7e73fa"
 dependencies = [
  "cpal",
  "lewton",
@@ -2624,6 +2718,12 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "rustc-demangle"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b"
+
 [[package]]
 name = "rustc-hash"
 version = "1.1.0"
@@ -2631,12 +2731,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
 [[package]]
-name = "rustc_version"
-version = "0.2.3"
+name = "ruzstd"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+checksum = "8cada0ef59efa6a5f4dc5e491f93d9f31e3fc7758df421ff1de8a706338e1100"
 dependencies = [
- "semver",
+ "byteorder",
+ "twox-hash",
 ]
 
 [[package]]
@@ -2666,21 +2767,6 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
-[[package]]
-name = "semver"
-version = "0.9.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
-dependencies = [
- "semver-parser",
-]
-
-[[package]]
-name = "semver-parser"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-
 [[package]]
 name = "serde"
 version = "1.0.152"
@@ -2696,8 +2782,8 @@ version = "1.0.152"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
 dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
@@ -2712,21 +2798,6 @@ dependencies = [
  "serde",
 ]
 
-[[package]]
-name = "sha1"
-version = "0.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770"
-dependencies = [
- "sha1_smol",
-]
-
-[[package]]
-name = "sha1_smol"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
-
 [[package]]
 name = "sharded-slab"
 version = "0.1.4"
@@ -2785,67 +2856,12 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
 
-[[package]]
-name = "stdweb"
-version = "0.4.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
-dependencies = [
- "discard",
- "rustc_version",
- "stdweb-derive",
- "stdweb-internal-macros",
- "stdweb-internal-runtime",
- "wasm-bindgen",
-]
-
-[[package]]
-name = "stdweb-derive"
-version = "0.5.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef"
-dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
- "serde",
- "serde_derive",
- "syn 1.0.107",
-]
-
-[[package]]
-name = "stdweb-internal-macros"
-version = "0.2.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11"
-dependencies = [
- "base-x",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
- "serde",
- "serde_derive",
- "serde_json",
- "sha1",
- "syn 1.0.107",
-]
-
-[[package]]
-name = "stdweb-internal-runtime"
-version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0"
-
 [[package]]
 name = "strsim"
 version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
 
-[[package]]
-name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
 [[package]]
 name = "svg_fmt"
 version = "0.4.1"
@@ -2869,22 +2885,45 @@ version = "1.0.107"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
 dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
+dependencies = [
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "unicode-ident",
 ]
 
+[[package]]
+name = "sysinfo"
+version = "0.28.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4c2f3ca6693feb29a89724516f016488e9aafc7f37264f898593ee4b942f31b"
+dependencies = [
+ "cfg-if",
+ "core-foundation-sys 0.8.3",
+ "libc",
+ "ntapi",
+ "once_cell",
+ "winapi",
+]
+
 [[package]]
 name = "taffy"
-version = "0.1.0"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec27dea659b100d489dffa57cf0efc6d7bfefb119af817b92cc14006c0b214e3"
+checksum = "fab62c50c3d17993e7f0c72932e51ceeac5ec2b51c225fda8529d606159c99d8"
 dependencies = [
  "arrayvec",
- "hash32",
- "hash32-derive",
  "num-traits",
- "typenum",
+ "slotmap",
 ]
 
 [[package]]
@@ -2898,22 +2937,22 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.38"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.38"
+version = "1.0.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
 dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
- "syn 1.0.107",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
+ "syn 2.0.15",
 ]
 
 [[package]]
@@ -2949,6 +2988,23 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "toml_datetime"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
+
+[[package]]
+name = "toml_edit"
+version = "0.19.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
 [[package]]
 name = "tracing"
 version = "0.1.37"
@@ -2967,8 +3023,8 @@ version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
 dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
 ]
 
@@ -3029,10 +3085,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633"
 
 [[package]]
-name = "typenum"
-version = "1.16.0"
+name = "twox-hash"
+version = "1.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
+checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
+dependencies = [
+ "cfg-if",
+ "static_assertions",
+]
 
 [[package]]
 name = "unicode-ident"
@@ -3111,9 +3171,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -3121,24 +3181,24 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.33"
+version = "0.4.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
+checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -3148,22 +3208,22 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5"
 dependencies = [
- "quote 1.0.23",
+ "quote 1.0.26",
  "wasm-bindgen-macro-support",
 ]
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6"
 dependencies = [
- "proc-macro2 1.0.49",
- "quote 1.0.23",
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
  "syn 1.0.107",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
@@ -3171,15 +3231,26 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.83"
+version = "0.2.84"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d"
+
+[[package]]
+name = "wayland-scanner"
+version = "0.29.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
+dependencies = [
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
+ "xml-rs",
+]
 
 [[package]]
 name = "web-sys"
-version = "0.3.60"
+version = "0.3.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
+checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -3187,16 +3258,18 @@ dependencies = [
 
 [[package]]
 name = "wgpu"
-version = "0.14.2"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81f643110d228fd62a60c5ed2ab56c4d5b3704520bd50561174ec4ec74932937"
+checksum = "d745a1b6d91d85c33defbb29f0eee0450e1d2614d987e14bf6baf26009d132d7"
 dependencies = [
  "arrayvec",
+ "cfg-if",
  "js-sys",
  "log",
  "naga",
  "parking_lot",
- "raw-window-handle 0.5.0",
+ "profiling",
+ "raw-window-handle",
  "smallvec",
  "static_assertions",
  "wasm-bindgen",
@@ -3209,21 +3282,20 @@ dependencies = [
 
 [[package]]
 name = "wgpu-core"
-version = "0.14.2"
+version = "0.15.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6000d1284ef8eec6076fd5544a73125fd7eb9b635f18dceeb829d826f41724ca"
+checksum = "7131408d940e335792645a98f03639573b0480e9e2e7cddbbab74f7c6d9f3fff"
 dependencies = [
  "arrayvec",
  "bit-vec",
  "bitflags",
- "cfg_aliases",
  "codespan-reporting",
  "fxhash",
  "log",
  "naga",
  "parking_lot",
  "profiling",
- "raw-window-handle 0.5.0",
+ "raw-window-handle",
  "smallvec",
  "thiserror",
  "web-sys",
@@ -3233,9 +3305,9 @@ dependencies = [
 
 [[package]]
 name = "wgpu-hal"
-version = "0.14.1"
+version = "0.15.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cc320a61acb26be4f549c9b1b53405c10a223fbfea363ec39474c32c348d12f"
+checksum = "bdcf61a283adc744bb5453dd88ea91f3f86d5ca6b027661c6c73c7734ae0288b"
 dependencies = [
  "android_system_properties",
  "arrayvec",
@@ -3249,9 +3321,12 @@ dependencies = [
  "fxhash",
  "glow",
  "gpu-alloc",
+ "gpu-allocator",
  "gpu-descriptor",
+ "hassle-rs",
  "js-sys",
  "khronos-egl",
+ "libc",
  "libloading",
  "log",
  "metal",
@@ -3260,7 +3335,7 @@ dependencies = [
  "parking_lot",
  "profiling",
  "range-alloc",
- "raw-window-handle 0.5.0",
+ "raw-window-handle",
  "renderdoc-sys",
  "smallvec",
  "thiserror",
@@ -3272,13 +3347,21 @@ dependencies = [
 
 [[package]]
 name = "wgpu-types"
-version = "0.14.1"
+version = "0.15.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb6b28ef22cac17b9109b25b3bf8c9a103eeb293d7c5f78653979b09140375f6"
+checksum = "32444e121b0bd00cb02c0de32fde457a9491bd44e03e7a5db6df9b1da2f6f110"
 dependencies = [
  "bitflags",
+ "js-sys",
+ "web-sys",
 ]
 
+[[package]]
+name = "widestring"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983"
+
 [[package]]
 name = "winapi"
 version = "0.3.9"
@@ -3310,19 +3393,6 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
-[[package]]
-name = "windows"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57b543186b344cc61c85b5aab0d2e3adf4e0f99bc076eff9aa5927bcc0b8a647"
-dependencies = [
- "windows_aarch64_msvc 0.37.0",
- "windows_i686_gnu 0.37.0",
- "windows_i686_msvc 0.37.0",
- "windows_x86_64_gnu 0.37.0",
- "windows_x86_64_msvc 0.37.0",
-]
-
 [[package]]
 name = "windows"
 version = "0.43.0"
@@ -3330,152 +3400,146 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04662ed0e3e5630dfa9b26e4cb823b817f1a9addda855d973a9458c236556244"
 dependencies = [
  "windows_aarch64_gnullvm",
- "windows_aarch64_msvc 0.42.1",
- "windows_i686_gnu 0.42.1",
- "windows_i686_msvc 0.42.1",
- "windows_x86_64_gnu 0.42.1",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
  "windows_x86_64_gnullvm",
- "windows_x86_64_msvc 0.42.1",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
-name = "windows-sys"
-version = "0.36.1"
+name = "windows"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b"
 dependencies = [
- "windows_aarch64_msvc 0.36.1",
- "windows_i686_gnu 0.36.1",
- "windows_i686_msvc 0.36.1",
- "windows_x86_64_gnu 0.36.1",
- "windows_x86_64_msvc 0.36.1",
+ "windows-implement",
+ "windows-interface",
+ "windows-targets",
 ]
 
 [[package]]
-name = "windows-sys"
-version = "0.42.0"
+name = "windows"
+version = "0.46.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc 0.42.1",
- "windows_i686_gnu 0.42.1",
- "windows_i686_msvc 0.42.1",
- "windows_x86_64_gnu 0.42.1",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc 0.42.1",
+ "windows-targets",
 ]
 
 [[package]]
-name = "windows_aarch64_gnullvm"
-version = "0.42.1"
+name = "windows-implement"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
-
-[[package]]
-name = "windows_aarch64_msvc"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+checksum = "6ce87ca8e3417b02dc2a8a22769306658670ec92d78f1bd420d6310a67c245c6"
+dependencies = [
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
+ "syn 1.0.107",
+]
 
 [[package]]
-name = "windows_aarch64_msvc"
-version = "0.37.0"
+name = "windows-interface"
+version = "0.44.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2623277cb2d1c216ba3b578c0f3cf9cdebeddb6e66b1b218bb33596ea7769c3a"
+checksum = "853f69a591ecd4f810d29f17e902d40e349fb05b0b11fff63b08b826bfe39c7f"
+dependencies = [
+ "proc-macro2 1.0.56",
+ "quote 1.0.26",
+ "syn 1.0.107",
+]
 
 [[package]]
-name = "windows_aarch64_msvc"
-version = "0.42.1"
+name = "windows-sys"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.36.1"
+name = "windows-sys"
+version = "0.45.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.37.0"
+name = "windows-targets"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3925fd0b0b804730d44d4b6278c50f9699703ec49bcd628020f46f4ba07d9e1"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.42.1"
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
 
 [[package]]
-name = "windows_i686_msvc"
-version = "0.36.1"
+name = "windows_aarch64_msvc"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
 
 [[package]]
-name = "windows_i686_msvc"
-version = "0.37.0"
+name = "windows_i686_gnu"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce907ac74fe331b524c1298683efbf598bb031bc84d5e274db2083696d07c57c"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.42.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.36.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
-
-[[package]]
-name = "windows_x86_64_gnu"
-version = "0.37.0"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2babfba0828f2e6b32457d5341427dcbb577ceef556273229959ac23a10af33d"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.42.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.36.1"
+version = "0.42.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.37.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4dd6dc7df2d84cf7b33822ed5b86318fb1781948e9663bacd047fc9dd52259d"
-
-[[package]]
-name = "windows_x86_64_msvc"
-version = "0.42.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
 
 [[package]]
 name = "winit"
-version = "0.27.5"
+version = "0.28.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bb796d6fbd86b2fd896c9471e6f04d39d750076ebe5680a3958f00f5ab97657c"
+checksum = "4f504e8c117b9015f618774f8d58cd4781f5a479bc41079c064f974cbb253874"
 dependencies = [
+ "android-activity",
  "bitflags",
- "cocoa",
+ "cfg_aliases",
  "core-foundation",
  "core-graphics",
  "dispatch",
@@ -3483,20 +3547,29 @@ dependencies = [
  "libc",
  "log",
  "mio",
- "ndk 0.7.0",
- "ndk-glue",
- "objc",
+ "ndk",
+ "objc2",
  "once_cell",
- "parking_lot",
+ "orbclient",
  "percent-encoding",
- "raw-window-handle 0.4.3",
- "raw-window-handle 0.5.0",
+ "raw-window-handle",
+ "redox_syscall 0.3.5",
  "wasm-bindgen",
+ "wayland-scanner",
  "web-sys",
- "windows-sys 0.36.1",
+ "windows-sys 0.45.0",
  "x11-dl",
 ]
 
+[[package]]
+name = "winnow"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28"
+dependencies = [
+ "memchr",
+]
+
 [[package]]
 name = "x11-dl"
 version = "2.20.1"
@@ -3513,3 +3586,9 @@ name = "xi-unicode"
 version = "0.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a"
+
+[[package]]
+name = "xml-rs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
diff --git a/Cargo.toml b/Cargo.toml
index 45d190d8919d200659b838873cce8e721db05dc0..2b84448834d37b946eeb3b523aa5884561e4b1f9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "micro_ldtk"
-version = "0.2.0"
+version = "0.3.0-beta.1"
 edition = "2021"
 
 authors = [
@@ -9,13 +9,19 @@ authors = [
 repository = "https://lab.lcr.gr/microhacks/bevy-micro-ldtk.git"
 license = "Apache-2.0"
 
+[features]
+default = ["ldtk_1_2_5"]
+ldtk_1_2_5 = []
+ldtk_1_2_4 = []
+no_panic = []
+
 [dependencies]
-bevy = "0.9.1"
+bevy = "0.10.1"
 anyhow = "1.0.66"
+thiserror = "1.0.40"
 log = "0.4.17"
 serde = "1.0.147"
 serde_json = "1.0.87"
-ldtk_rust = "0.6.0"
 num-traits = "0.2.15"
 quadtree_rs = "0.1.2"
 
diff --git a/src/assets.rs b/src/assets.rs
deleted file mode 100644
index 8e450e2185758a2da2cb54aa080877b3b80daa7f..0000000000000000000000000000000000000000
--- a/src/assets.rs
+++ /dev/null
@@ -1,119 +0,0 @@
-use std::collections::HashMap;
-use std::ops::{Deref, DerefMut};
-
-use anyhow::Error;
-use bevy::asset::{AssetEvent, AssetLoader, Assets, BoxedFuture, LoadContext, LoadedAsset};
-use bevy::prelude::{EventReader, EventWriter, Res, ResMut, Resource};
-use bevy::reflect::TypeUuid;
-use ldtk_rust::Project;
-use serde_json::Value;
-
-use crate::utils::SerdeClone;
-use crate::{LdtkLevel, LevelDataUpdated};
-
-#[derive(TypeUuid)]
-#[uuid = "292a8918-9487-11ed-8dd2-43b6f36cb076"]
-pub struct LdtkProject(pub Project);
-impl Deref for LdtkProject {
-	type Target = Project;
-	fn deref(&self) -> &Self::Target {
-		&self.0
-	}
-}
-impl DerefMut for LdtkProject {
-	fn deref_mut(&mut self) -> &mut Self::Target {
-		&mut self.0
-	}
-}
-
-impl LdtkProject {}
-
-#[derive(Default)]
-pub struct LdtkLoader;
-impl AssetLoader for LdtkLoader {
-	fn load<'a>(
-		&'a self,
-		bytes: &'a [u8],
-		load_context: &'a mut LoadContext,
-	) -> BoxedFuture<'a, anyhow::Result<(), Error>> {
-		Box::pin(async move {
-			let mut ldtk: Project = serde_json::from_slice(bytes)?;
-			if ldtk.external_levels {
-				ldtk.load_external_levels(load_context.path());
-			}
-			load_context.set_default_asset(LoadedAsset::new(LdtkProject(ldtk)));
-			Ok(())
-		})
-	}
-
-	fn extensions(&self) -> &[&str] {
-		&["ldtk"]
-	}
-}
-
-#[derive(Resource, Default)]
-pub struct LevelIndex(pub HashMap<String, LdtkLevel>);
-impl Deref for LevelIndex {
-	type Target = HashMap<String, LdtkLevel>;
-	fn deref(&self) -> &Self::Target {
-		&self.0
-	}
-}
-impl DerefMut for LevelIndex {
-	fn deref_mut(&mut self) -> &mut Self::Target {
-		&mut self.0
-	}
-}
-
-#[derive(Default)]
-pub struct TileMetadata(pub HashMap<i64, Value>);
-
-#[derive(Resource, Default)]
-pub struct TilesetIndex(pub HashMap<String, TileMetadata>);
-impl Deref for TilesetIndex {
-	type Target = HashMap<String, TileMetadata>;
-	fn deref(&self) -> &Self::Target {
-		&self.0
-	}
-}
-impl DerefMut for TilesetIndex {
-	fn deref_mut(&mut self) -> &mut Self::Target {
-		&mut self.0
-	}
-}
-
-pub fn handle_ldtk_project_events(
-	mut events: EventReader<AssetEvent<LdtkProject>>,
-	assets: Res<Assets<LdtkProject>>,
-	mut level_index: ResMut<LevelIndex>,
-	mut tilset_index: ResMut<TilesetIndex>,
-	mut update_events: EventWriter<LevelDataUpdated>,
-) {
-	for event in events.iter() {
-		match event {
-			AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
-				if let Some(LdtkProject(project)) = assets.get(handle) {
-					for level in &project.levels {
-						level_index.insert(
-							level.identifier.clone(),
-							LdtkLevel::from(level.serde_clone()),
-						);
-						update_events.send(LevelDataUpdated(level.identifier.clone()));
-					}
-
-					for tileset in &project.defs.tilesets {
-						let mut tile_meta = HashMap::new();
-						for custom in &tileset.custom_data {
-							tile_meta.insert(
-								custom.tile_id,
-								serde_json::from_str(&custom.data).unwrap(),
-							);
-						}
-						tilset_index.insert(tileset.identifier.clone(), TileMetadata(tile_meta));
-					}
-				}
-			}
-			_ => {}
-		}
-	}
-}
diff --git a/src/assets/asset_events.rs b/src/assets/asset_events.rs
new file mode 100644
index 0000000000000000000000000000000000000000..1a561e57308984579ede97d313965043b09f1f9c
--- /dev/null
+++ b/src/assets/asset_events.rs
@@ -0,0 +1,42 @@
+use std::collections::HashMap;
+
+use bevy::prelude::*;
+
+use crate::ldtk::Project;
+use crate::{LdtkLevel, LevelDataUpdated, LevelIndex, TileMetadata, TilesetIndex};
+
+pub fn handle_ldtk_project_events(
+	mut events: EventReader<AssetEvent<Project>>,
+	assets: Res<Assets<Project>>,
+	mut level_index: ResMut<LevelIndex>,
+	mut tilset_index: ResMut<TilesetIndex>,
+	mut update_events: EventWriter<LevelDataUpdated>,
+) {
+	for event in events.iter() {
+		match event {
+			AssetEvent::Created { handle } | AssetEvent::Modified { handle } => {
+				if let Some(project) = assets.get(handle) {
+					for level in &project.levels {
+						level_index.insert(
+							level.identifier.clone(),
+							LdtkLevel::from(level.serde_clone()),
+						);
+						update_events.send(LevelDataUpdated(level.identifier.clone()));
+					}
+
+					for tileset in &project.defs.tilesets {
+						let mut tile_meta = HashMap::new();
+						for custom in &tileset.custom_data {
+							tile_meta.insert(
+								custom.tile_id,
+								serde_json::from_str(&custom.data).unwrap(),
+							);
+						}
+						tilset_index.insert(tileset.identifier.clone(), TileMetadata(tile_meta));
+					}
+				}
+			}
+			_ => {}
+		}
+	}
+}
diff --git a/src/assets/asset_storage.rs b/src/assets/asset_storage.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8f820522814d69c4df1b006e728030e121bcdc03
--- /dev/null
+++ b/src/assets/asset_storage.rs
@@ -0,0 +1,35 @@
+use std::collections::HashMap;
+use std::ops::{Deref, DerefMut};
+
+use bevy::prelude::Resource;
+
+#[derive(Resource, Default)]
+pub struct LevelIndex(pub HashMap<String, LdtkLevel>);
+impl Deref for LevelIndex {
+	type Target = HashMap<String, LdtkLevel>;
+	fn deref(&self) -> &Self::Target {
+		&self.0
+	}
+}
+impl DerefMut for LevelIndex {
+	fn deref_mut(&mut self) -> &mut Self::Target {
+		&mut self.0
+	}
+}
+
+#[derive(Default)]
+pub struct TileMetadata(pub HashMap<i64, Value>);
+
+#[derive(Resource, Default)]
+pub struct TilesetIndex(pub HashMap<String, TileMetadata>);
+impl Deref for TilesetIndex {
+	type Target = HashMap<String, TileMetadata>;
+	fn deref(&self) -> &Self::Target {
+		&self.0
+	}
+}
+impl DerefMut for TilesetIndex {
+	fn deref_mut(&mut self) -> &mut Self::Target {
+		&mut self.0
+	}
+}
diff --git a/src/assets/mod.rs b/src/assets/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..505220168d4b2da1af73b1c8191dbcdcc03456a1
--- /dev/null
+++ b/src/assets/mod.rs
@@ -0,0 +1,5 @@
+mod asset_events;
+mod asset_storage;
+
+pub use asset_events::*;
+pub use asset_storage::*;
diff --git a/src/ldtk/data_1_2_4.rs b/src/ldtk/data_1_2_4.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a1f9342ffda69c51a5d99e213f0e2374dc1079ea
--- /dev/null
+++ b/src/ldtk/data_1_2_4.rs
@@ -0,0 +1,1818 @@
+// Example code that deserializes and serializes the model.
+// extern crate serde;
+// #[macro_use]
+// extern crate serde_derive;
+// extern crate serde_json;
+//
+// use generated_module::Project;
+//
+// fn main() {
+//     let json = r#"{"answer": 42}"#;
+//     let model: Project = serde_json::from_str(&json).unwrap();
+// }
+
+use std::collections::HashMap;
+
+use serde::{Deserialize, Serialize};
+
+/// This file is a JSON schema of files created by LDtk level editor (https://ldtk.io).
+///
+/// This is the root of any Project JSON file. It contains:  - the project settings, - an
+/// array of levels, - a group of definitions (that can probably be safely ignored for most
+/// users).
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Project {
+	/// This object is not actually used by LDtk. It ONLY exists to force explicit references to
+	/// all types, to make sure QuickType finds them and integrate all of them. Otherwise,
+	/// Quicktype will drop types that are not explicitely used.
+	#[serde(rename = "__FORCED_REFS")]
+	pub forced_refs: Option<ForcedRefs>,
+
+	/// LDtk application build identifier.<br/>  This is only used to identify the LDtk version
+	/// that generated this particular project file, which can be useful for specific bug fixing.
+	/// Note that the build identifier is just the date of the release, so it's not unique to
+	/// each user (one single global ID per LDtk public release), and as a result, completely
+	/// anonymous.
+	#[serde(rename = "appBuildId")]
+	pub app_build_id: f64,
+
+	/// Number of backup files to keep, if the `backupOnSave` is TRUE
+	#[serde(rename = "backupLimit")]
+	pub backup_limit: i64,
+
+	/// If TRUE, an extra copy of the project will be created in a sub folder, when saving.
+	#[serde(rename = "backupOnSave")]
+	pub backup_on_save: bool,
+
+	/// Project background color
+	#[serde(rename = "bgColor")]
+	pub bg_color: String,
+
+	/// An array of command lines that can be ran manually by the user
+	#[serde(rename = "customCommands")]
+	pub custom_commands: Vec<LdtkCustomCommand>,
+
+	/// Default grid size for new layers
+	#[serde(rename = "defaultGridSize")]
+	pub default_grid_size: i64,
+
+	/// Default background color of levels
+	#[serde(rename = "defaultLevelBgColor")]
+	pub default_level_bg_color: String,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  Default new level height
+	#[serde(rename = "defaultLevelHeight")]
+	pub default_level_height: Option<i64>,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  Default new level width
+	#[serde(rename = "defaultLevelWidth")]
+	pub default_level_width: Option<i64>,
+
+	/// Default X pivot (0 to 1) for new entities
+	#[serde(rename = "defaultPivotX")]
+	pub default_pivot_x: f64,
+
+	/// Default Y pivot (0 to 1) for new entities
+	#[serde(rename = "defaultPivotY")]
+	pub default_pivot_y: f64,
+
+	/// A structure containing all the definitions of this project
+	#[serde(rename = "defs")]
+	pub defs: Definitions,
+
+	/// If TRUE, the exported PNGs will include the level background (color or image).
+	#[serde(rename = "exportLevelBg")]
+	pub export_level_bg: bool,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 0.9.3  Replaced
+	/// by: `imageExportMode`
+	#[serde(rename = "exportPng")]
+	pub export_png: Option<bool>,
+
+	/// If TRUE, a Tiled compatible file will also be generated along with the LDtk JSON file
+	/// (default is FALSE)
+	#[serde(rename = "exportTiled")]
+	pub export_tiled: bool,
+
+	/// If TRUE, one file will be saved for the project (incl. all its definitions) and one file
+	/// in a sub-folder for each level.
+	#[serde(rename = "externalLevels")]
+	pub external_levels: bool,
+
+	/// An array containing various advanced flags (ie. options or other states). Possible
+	/// values: `DiscardPreCsvIntGrid`, `ExportPreCsvIntGridFormat`, `IgnoreBackupSuggest`,
+	/// `PrependIndexToLevelFileNames`, `MultiWorlds`, `UseMultilinesType`
+	#[serde(rename = "flags")]
+	pub flags: Vec<Flag>,
+
+	/// Naming convention for Identifiers (first-letter uppercase, full uppercase etc.) Possible
+	/// values: `Capitalize`, `Uppercase`, `Lowercase`, `Free`
+	#[serde(rename = "identifierStyle")]
+	pub identifier_style: IdentifierStyle,
+
+	/// Unique project identifier
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// "Image export" option when saving project. Possible values: `None`, `OneImagePerLayer`,
+	/// `OneImagePerLevel`, `LayersAndLevels`
+	#[serde(rename = "imageExportMode")]
+	pub image_export_mode: ImageExportMode,
+
+	/// File format version
+	#[serde(rename = "jsonVersion")]
+	pub json_version: String,
+
+	/// The default naming convention for level identifiers.
+	#[serde(rename = "levelNamePattern")]
+	pub level_name_pattern: String,
+
+	/// All levels. The order of this array is only relevant in `LinearHorizontal` and
+	/// `linearVertical` world layouts (see `worldLayout` value).<br/>  Otherwise, you should
+	/// refer to the `worldX`,`worldY` coordinates of each Level.
+	#[serde(rename = "levels")]
+	pub levels: Vec<Level>,
+
+	/// If TRUE, the Json is partially minified (no indentation, nor line breaks, default is
+	/// FALSE)
+	#[serde(rename = "minifyJson")]
+	pub minify_json: bool,
+
+	/// Next Unique integer ID available
+	#[serde(rename = "nextUid")]
+	pub next_uid: i64,
+
+	/// File naming pattern for exported PNGs
+	#[serde(rename = "pngFilePattern")]
+	pub png_file_pattern: Option<String>,
+
+	/// If TRUE, a very simplified will be generated on saving, for quicker & easier engine
+	/// integration.
+	#[serde(rename = "simplifiedExport")]
+	pub simplified_export: bool,
+
+	/// All instances of entities that have their `exportToToc` flag enabled are listed in this
+	/// array.
+	#[serde(rename = "toc")]
+	pub toc: Vec<LdtkTableOfContentEntry>,
+
+	/// This optional description is used by LDtk Samples to show up some informations and
+	/// instructions.
+	#[serde(rename = "tutorialDesc")]
+	pub tutorial_desc: Option<String>,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  Height of the world grid in pixels.
+	#[serde(rename = "worldGridHeight")]
+	pub world_grid_height: Option<i64>,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  Width of the world grid in pixels.
+	#[serde(rename = "worldGridWidth")]
+	pub world_grid_width: Option<i64>,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  An enum that describes how levels are organized in
+	/// this project (ie. linearly or in a 2D space). Possible values: &lt;`null`&gt;, `Free`,
+	/// `GridVania`, `LinearHorizontal`, `LinearVertical`
+	#[serde(rename = "worldLayout")]
+	pub world_layout: Option<WorldLayout>,
+
+	/// This array is not used yet in current LDtk version (so, for now, it's always
+	/// empty).<br/><br/>In a later update, it will be possible to have multiple Worlds in a
+	/// single project, each containing multiple Levels.<br/><br/>What will change when "Multiple
+	/// worlds" support will be added to LDtk:<br/><br/> - in current version, a LDtk project
+	/// file can only contain a single world with multiple levels in it. In this case, levels and
+	/// world layout related settings are stored in the root of the JSON.<br/> - after the
+	/// "Multiple worlds" update, there will be a `worlds` array in root, each world containing
+	/// levels and layout settings. Basically, it's pretty much only about moving the `levels`
+	/// array to the `worlds` array, along with world layout related values (eg. `worldGridWidth`
+	/// etc).<br/><br/>If you want to start supporting this future update easily, please refer to
+	/// this documentation: https://github.com/deepnight/ldtk/issues/231
+	#[serde(rename = "worlds")]
+	pub worlds: Vec<World>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LdtkCustomCommand {
+	#[serde(rename = "command")]
+	pub command: String,
+
+	/// Possible values: `Manual`, `AfterLoad`, `BeforeSave`, `AfterSave`
+	#[serde(rename = "when")]
+	pub when: When,
+}
+
+/// If you're writing your own LDtk importer, you should probably just ignore *most* stuff in
+/// the `defs` section, as it contains data that are mostly important to the editor. To keep
+/// you away from the `defs` section and avoid some unnecessary JSON parsing, important data
+/// from definitions is often duplicated in fields prefixed with a double underscore (eg.
+/// `__identifier` or `__type`).  The 2 only definition types you might need here are
+/// **Tilesets** and **Enums**.
+///
+/// A structure containing all the definitions of this project
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Definitions {
+	/// All entities definitions, including their custom fields
+	#[serde(rename = "entities")]
+	pub entities: Vec<EntityDefinition>,
+
+	/// All internal enums
+	#[serde(rename = "enums")]
+	pub enums: Vec<EnumDefinition>,
+
+	/// Note: external enums are exactly the same as `enums`, except they have a `relPath` to
+	/// point to an external source file.
+	#[serde(rename = "externalEnums")]
+	pub external_enums: Vec<EnumDefinition>,
+
+	/// All layer definitions
+	#[serde(rename = "layers")]
+	pub layers: Vec<LayerDefinition>,
+
+	/// All custom fields available to all levels.
+	#[serde(rename = "levelFields")]
+	pub level_fields: Vec<FieldDefinition>,
+
+	/// All tilesets
+	#[serde(rename = "tilesets")]
+	pub tilesets: Vec<TilesetDefinition>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EntityDefinition {
+	/// Base entity color
+	#[serde(rename = "color")]
+	pub color: String,
+
+	/// If enabled, all instances of this entity will be listed in the project "Table of content"
+	/// object.
+	#[serde(rename = "exportToToc")]
+	pub export_to_toc: bool,
+
+	/// Array of field definitions
+	#[serde(rename = "fieldDefs")]
+	pub field_defs: Vec<FieldDefinition>,
+
+	#[serde(rename = "fillOpacity")]
+	pub fill_opacity: f64,
+
+	/// Pixel height
+	#[serde(rename = "height")]
+	pub height: i64,
+
+	#[serde(rename = "hollow")]
+	pub hollow: bool,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Only applies to entities resizable on both X/Y. If TRUE, the entity instance width/height
+	/// will keep the same aspect ratio as the definition.
+	#[serde(rename = "keepAspectRatio")]
+	pub keep_aspect_ratio: bool,
+
+	/// Possible values: `DiscardOldOnes`, `PreventAdding`, `MoveLastOne`
+	#[serde(rename = "limitBehavior")]
+	pub limit_behavior: LimitBehavior,
+
+	/// If TRUE, the maxCount is a "per world" limit, if FALSE, it's a "per level". Possible
+	/// values: `PerLayer`, `PerLevel`, `PerWorld`
+	#[serde(rename = "limitScope")]
+	pub limit_scope: LimitScope,
+
+	#[serde(rename = "lineOpacity")]
+	pub line_opacity: f64,
+
+	/// Max instances count
+	#[serde(rename = "maxCount")]
+	pub max_count: i64,
+
+	/// An array of 4 dimensions for the up/right/down/left borders (in this order) when using
+	/// 9-slice mode for `tileRenderMode`.<br/>  If the tileRenderMode is not NineSlice, then
+	/// this array is empty.<br/>  See: https://en.wikipedia.org/wiki/9-slice_scaling
+	#[serde(rename = "nineSliceBorders")]
+	pub nine_slice_borders: Vec<i64>,
+
+	/// Pivot X coordinate (from 0 to 1.0)
+	#[serde(rename = "pivotX")]
+	pub pivot_x: f64,
+
+	/// Pivot Y coordinate (from 0 to 1.0)
+	#[serde(rename = "pivotY")]
+	pub pivot_y: f64,
+
+	/// Possible values: `Rectangle`, `Ellipse`, `Tile`, `Cross`
+	#[serde(rename = "renderMode")]
+	pub render_mode: RenderMode,
+
+	/// If TRUE, the entity instances will be resizable horizontally
+	#[serde(rename = "resizableX")]
+	pub resizable_x: bool,
+
+	/// If TRUE, the entity instances will be resizable vertically
+	#[serde(rename = "resizableY")]
+	pub resizable_y: bool,
+
+	/// Display entity name in editor
+	#[serde(rename = "showName")]
+	pub show_name: bool,
+
+	/// An array of strings that classifies this entity
+	#[serde(rename = "tags")]
+	pub tags: Vec<String>,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 1.2.0  Replaced
+	/// by: `tileRect`
+	#[serde(rename = "tileId")]
+	pub tile_id: Option<i64>,
+
+	#[serde(rename = "tileOpacity")]
+	pub tile_opacity: f64,
+
+	/// An object representing a rectangle from an existing Tileset
+	#[serde(rename = "tileRect")]
+	pub tile_rect: Option<TilesetRectangle>,
+
+	/// An enum describing how the the Entity tile is rendered inside the Entity bounds. Possible
+	/// values: `Cover`, `FitInside`, `Repeat`, `Stretch`, `FullSizeCropped`,
+	/// `FullSizeUncropped`, `NineSlice`
+	#[serde(rename = "tileRenderMode")]
+	pub tile_render_mode: TileRenderMode,
+
+	/// Tileset ID used for optional tile display
+	#[serde(rename = "tilesetId")]
+	pub tileset_id: Option<i64>,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// Pixel width
+	#[serde(rename = "width")]
+	pub width: i64,
+}
+
+/// This section is mostly only intended for the LDtk editor app itself. You can safely
+/// ignore it.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct FieldDefinition {
+	/// Human readable value type. Possible values: `Int, Float, String, Bool, Color,
+	/// ExternEnum.XXX, LocalEnum.XXX, Point, FilePath`.<br/>  If the field is an array, this
+	/// field will look like `Array<...>` (eg. `Array<Int>`, `Array<Point>` etc.)<br/>  NOTE: if
+	/// you enable the advanced option **Use Multilines type**, you will have "*Multilines*"
+	/// instead of "*String*" when relevant.
+	#[serde(rename = "__type")]
+	pub field_definition_type: String,
+
+	/// Optional list of accepted file extensions for FilePath value type. Includes the dot:
+	/// `.ext`
+	#[serde(rename = "acceptFileTypes")]
+	pub accept_file_types: Option<Vec<String>>,
+
+	/// Possible values: `Any`, `OnlySame`, `OnlyTags`
+	#[serde(rename = "allowedRefs")]
+	pub allowed_refs: AllowedRefs,
+
+	#[serde(rename = "allowedRefTags")]
+	pub allowed_ref_tags: Vec<String>,
+
+	#[serde(rename = "allowOutOfLevelRef")]
+	pub allow_out_of_level_ref: bool,
+
+	/// Array max length
+	#[serde(rename = "arrayMaxLength")]
+	pub array_max_length: Option<i64>,
+
+	/// Array min length
+	#[serde(rename = "arrayMinLength")]
+	pub array_min_length: Option<i64>,
+
+	#[serde(rename = "autoChainRef")]
+	pub auto_chain_ref: bool,
+
+	/// TRUE if the value can be null. For arrays, TRUE means it can contain null values
+	/// (exception: array of Points can't have null values).
+	#[serde(rename = "canBeNull")]
+	pub can_be_null: bool,
+
+	/// Default value if selected value is null or invalid.
+	#[serde(rename = "defaultOverride")]
+	pub default_override: Option<serde_json::Value>,
+
+	/// User defined documentation for this field to provide help/tips to level designers about
+	/// accepted values.
+	#[serde(rename = "doc")]
+	pub doc: Option<String>,
+
+	#[serde(rename = "editorAlwaysShow")]
+	pub editor_always_show: bool,
+
+	#[serde(rename = "editorCutLongValues")]
+	pub editor_cut_long_values: bool,
+
+	/// Possible values: `Hidden`, `ValueOnly`, `NameAndValue`, `EntityTile`, `Points`,
+	/// `PointStar`, `PointPath`, `PointPathLoop`, `RadiusPx`, `RadiusGrid`,
+	/// `ArrayCountWithLabel`, `ArrayCountNoLabel`, `RefLinkBetweenPivots`,
+	/// `RefLinkBetweenCenters`
+	#[serde(rename = "editorDisplayMode")]
+	pub editor_display_mode: EditorDisplayMode,
+
+	/// Possible values: `Above`, `Center`, `Beneath`
+	#[serde(rename = "editorDisplayPos")]
+	pub editor_display_pos: EditorDisplayPos,
+
+	/// Possible values: `ZigZag`, `StraightArrow`, `CurvedArrow`, `ArrowsLine`, `DashedLine`
+	#[serde(rename = "editorLinkStyle")]
+	pub editor_link_style: EditorLinkStyle,
+
+	#[serde(rename = "editorShowInWorld")]
+	pub editor_show_in_world: bool,
+
+	#[serde(rename = "editorTextPrefix")]
+	pub editor_text_prefix: Option<String>,
+
+	#[serde(rename = "editorTextSuffix")]
+	pub editor_text_suffix: Option<String>,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// TRUE if the value is an array of multiple values
+	#[serde(rename = "isArray")]
+	pub is_array: bool,
+
+	/// Max limit for value, if applicable
+	#[serde(rename = "max")]
+	pub max: Option<f64>,
+
+	/// Min limit for value, if applicable
+	#[serde(rename = "min")]
+	pub min: Option<f64>,
+
+	/// Optional regular expression that needs to be matched to accept values. Expected format:
+	/// `/some_reg_ex/g`, with optional "i" flag.
+	#[serde(rename = "regex")]
+	pub regex: Option<String>,
+
+	#[serde(rename = "symmetricalRef")]
+	pub symmetrical_ref: bool,
+
+	/// Possible values: &lt;`null`&gt;, `LangPython`, `LangRuby`, `LangJS`, `LangLua`, `LangC`,
+	/// `LangHaxe`, `LangMarkdown`, `LangJson`, `LangXml`, `LangLog`
+	#[serde(rename = "textLanguageMode")]
+	pub text_language_mode: Option<TextLanguageMode>,
+
+	/// UID of the tileset used for a Tile
+	#[serde(rename = "tilesetUid")]
+	pub tileset_uid: Option<i64>,
+
+	/// Internal enum representing the possible field types. Possible values: F_Int, F_Float,
+	/// F_String, F_Text, F_Bool, F_Color, F_Enum(...), F_Point, F_Path, F_EntityRef, F_Tile
+	#[serde(rename = "type")]
+	pub purple_type: String,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// If TRUE, the color associated with this field will override the Entity or Level default
+	/// color in the editor UI. For Enum fields, this would be the color associated to their
+	/// values.
+	#[serde(rename = "useForSmartColor")]
+	pub use_for_smart_color: bool,
+}
+
+/// This object represents a custom sub rectangle in a Tileset image.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TilesetRectangle {
+	/// Height in pixels
+	#[serde(rename = "h")]
+	pub h: i64,
+
+	/// UID of the tileset
+	#[serde(rename = "tilesetUid")]
+	pub tileset_uid: i64,
+
+	/// Width in pixels
+	#[serde(rename = "w")]
+	pub w: i64,
+
+	/// X pixels coordinate of the top-left corner in the Tileset image
+	#[serde(rename = "x")]
+	pub x: i64,
+
+	/// Y pixels coordinate of the top-left corner in the Tileset image
+	#[serde(rename = "y")]
+	pub y: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EnumDefinition {
+	#[serde(rename = "externalFileChecksum")]
+	pub external_file_checksum: Option<String>,
+
+	/// Relative path to the external file providing this Enum
+	#[serde(rename = "externalRelPath")]
+	pub external_rel_path: Option<String>,
+
+	/// Tileset UID if provided
+	#[serde(rename = "iconTilesetUid")]
+	pub icon_tileset_uid: Option<i64>,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// An array of user-defined tags to organize the Enums
+	#[serde(rename = "tags")]
+	pub tags: Vec<String>,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// All possible enum values, with their optional Tile infos.
+	#[serde(rename = "values")]
+	pub values: Vec<EnumValueDefinition>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EnumValueDefinition {
+	/// An array of 4 Int values that refers to the tile in the tileset image: `[ x, y, width,
+	/// height ]`
+	#[serde(rename = "__tileSrcRect")]
+	pub tile_src_rect: Option<Vec<i64>>,
+
+	/// Optional color
+	#[serde(rename = "color")]
+	pub color: i64,
+
+	/// Enum value
+	#[serde(rename = "id")]
+	pub id: String,
+
+	/// The optional ID of the tile
+	#[serde(rename = "tileId")]
+	pub tile_id: Option<i64>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LayerDefinition {
+	/// Type of the layer (*IntGrid, Entities, Tiles or AutoLayer*)
+	#[serde(rename = "__type")]
+	pub layer_definition_type: String,
+
+	/// Contains all the auto-layer rule definitions.
+	#[serde(rename = "autoRuleGroups")]
+	pub auto_rule_groups: Vec<AutoLayerRuleGroup>,
+
+	#[serde(rename = "autoSourceLayerDefUid")]
+	pub auto_source_layer_def_uid: Option<i64>,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 1.2.0  Replaced
+	/// by: `tilesetDefUid`
+	#[serde(rename = "autoTilesetDefUid")]
+	pub auto_tileset_def_uid: Option<i64>,
+
+	/// Allow editor selections when the layer is not currently active.
+	#[serde(rename = "canSelectWhenInactive")]
+	pub can_select_when_inactive: bool,
+
+	/// Opacity of the layer (0 to 1.0)
+	#[serde(rename = "displayOpacity")]
+	pub display_opacity: f64,
+
+	/// An array of tags to forbid some Entities in this layer
+	#[serde(rename = "excludedTags")]
+	pub excluded_tags: Vec<String>,
+
+	/// Width and height of the grid in pixels
+	#[serde(rename = "gridSize")]
+	pub grid_size: i64,
+
+	/// Height of the optional "guide" grid in pixels
+	#[serde(rename = "guideGridHei")]
+	pub guide_grid_hei: i64,
+
+	/// Width of the optional "guide" grid in pixels
+	#[serde(rename = "guideGridWid")]
+	pub guide_grid_wid: i64,
+
+	#[serde(rename = "hideFieldsWhenInactive")]
+	pub hide_fields_when_inactive: bool,
+
+	/// Hide the layer from the list on the side of the editor view.
+	#[serde(rename = "hideInList")]
+	pub hide_in_list: bool,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Alpha of this layer when it is not the active one.
+	#[serde(rename = "inactiveOpacity")]
+	pub inactive_opacity: f64,
+
+	/// An array that defines extra optional info for each IntGrid value.<br/>  WARNING: the
+	/// array order is not related to actual IntGrid values! As user can re-order IntGrid values
+	/// freely, you may value "2" before value "1" in this array.
+	#[serde(rename = "intGridValues")]
+	pub int_grid_values: Vec<IntGridValueDefinition>,
+
+	/// Parallax horizontal factor (from -1 to 1, defaults to 0) which affects the scrolling
+	/// speed of this layer, creating a fake 3D (parallax) effect.
+	#[serde(rename = "parallaxFactorX")]
+	pub parallax_factor_x: f64,
+
+	/// Parallax vertical factor (from -1 to 1, defaults to 0) which affects the scrolling speed
+	/// of this layer, creating a fake 3D (parallax) effect.
+	#[serde(rename = "parallaxFactorY")]
+	pub parallax_factor_y: f64,
+
+	/// If true (default), a layer with a parallax factor will also be scaled up/down accordingly.
+	#[serde(rename = "parallaxScaling")]
+	pub parallax_scaling: bool,
+
+	/// X offset of the layer, in pixels (IMPORTANT: this should be added to the `LayerInstance`
+	/// optional offset)
+	#[serde(rename = "pxOffsetX")]
+	pub px_offset_x: i64,
+
+	/// Y offset of the layer, in pixels (IMPORTANT: this should be added to the `LayerInstance`
+	/// optional offset)
+	#[serde(rename = "pxOffsetY")]
+	pub px_offset_y: i64,
+
+	/// An array of tags to filter Entities that can be added to this layer
+	#[serde(rename = "requiredTags")]
+	pub required_tags: Vec<String>,
+
+	/// If the tiles are smaller or larger than the layer grid, the pivot value will be used to
+	/// position the tile relatively its grid cell.
+	#[serde(rename = "tilePivotX")]
+	pub tile_pivot_x: f64,
+
+	/// If the tiles are smaller or larger than the layer grid, the pivot value will be used to
+	/// position the tile relatively its grid cell.
+	#[serde(rename = "tilePivotY")]
+	pub tile_pivot_y: f64,
+
+	/// Reference to the default Tileset UID being used by this layer definition.<br/>
+	/// **WARNING**: some layer *instances* might use a different tileset. So most of the time,
+	/// you should probably use the `__tilesetDefUid` value found in layer instances.<br/>  Note:
+	/// since version 1.0.0, the old `autoTilesetDefUid` was removed and merged into this value.
+	#[serde(rename = "tilesetDefUid")]
+	pub tileset_def_uid: Option<i64>,
+
+	/// Type of the layer as Haxe Enum Possible values: `IntGrid`, `Entities`, `Tiles`,
+	/// `AutoLayer`
+	#[serde(rename = "type")]
+	pub purple_type: Type,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AutoLayerRuleGroup {
+	#[serde(rename = "active")]
+	pub active: bool,
+
+	/// *This field was removed in 1.0.0 and should no longer be used.*
+	#[serde(rename = "collapsed")]
+	pub collapsed: Option<bool>,
+
+	#[serde(rename = "isOptional")]
+	pub is_optional: bool,
+
+	#[serde(rename = "name")]
+	pub name: String,
+
+	#[serde(rename = "rules")]
+	pub rules: Vec<AutoLayerRuleDefinition>,
+
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	#[serde(rename = "usesWizard")]
+	pub uses_wizard: bool,
+}
+
+/// This complex section isn't meant to be used by game devs at all, as these rules are
+/// completely resolved internally by the editor before any saving. You should just ignore
+/// this part.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AutoLayerRuleDefinition {
+	/// If FALSE, the rule effect isn't applied, and no tiles are generated.
+	#[serde(rename = "active")]
+	pub active: bool,
+
+	/// When TRUE, the rule will prevent other rules to be applied in the same cell if it matches
+	/// (TRUE by default).
+	#[serde(rename = "breakOnMatch")]
+	pub break_on_match: bool,
+
+	/// Chances for this rule to be applied (0 to 1)
+	#[serde(rename = "chance")]
+	pub chance: f64,
+
+	/// Checker mode Possible values: `None`, `Horizontal`, `Vertical`
+	#[serde(rename = "checker")]
+	pub checker: Checker,
+
+	/// If TRUE, allow rule to be matched by flipping its pattern horizontally
+	#[serde(rename = "flipX")]
+	pub flip_x: bool,
+
+	/// If TRUE, allow rule to be matched by flipping its pattern vertically
+	#[serde(rename = "flipY")]
+	pub flip_y: bool,
+
+	/// Default IntGrid value when checking cells outside of level bounds
+	#[serde(rename = "outOfBoundsValue")]
+	pub out_of_bounds_value: Option<i64>,
+
+	/// Rule pattern (size x size)
+	#[serde(rename = "pattern")]
+	pub pattern: Vec<i64>,
+
+	/// If TRUE, enable Perlin filtering to only apply rule on specific random area
+	#[serde(rename = "perlinActive")]
+	pub perlin_active: bool,
+
+	#[serde(rename = "perlinOctaves")]
+	pub perlin_octaves: f64,
+
+	#[serde(rename = "perlinScale")]
+	pub perlin_scale: f64,
+
+	#[serde(rename = "perlinSeed")]
+	pub perlin_seed: f64,
+
+	/// X pivot of a tile stamp (0-1)
+	#[serde(rename = "pivotX")]
+	pub pivot_x: f64,
+
+	/// Y pivot of a tile stamp (0-1)
+	#[serde(rename = "pivotY")]
+	pub pivot_y: f64,
+
+	/// Pattern width & height. Should only be 1,3,5 or 7.
+	#[serde(rename = "size")]
+	pub size: i64,
+
+	/// Array of all the tile IDs. They are used randomly or as stamps, based on `tileMode` value.
+	#[serde(rename = "tileIds")]
+	pub tile_ids: Vec<i64>,
+
+	/// Defines how tileIds array is used Possible values: `Single`, `Stamp`
+	#[serde(rename = "tileMode")]
+	pub tile_mode: TileMode,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// X cell coord modulo
+	#[serde(rename = "xModulo")]
+	pub x_modulo: i64,
+
+	/// X cell start offset
+	#[serde(rename = "xOffset")]
+	pub x_offset: i64,
+
+	/// Y cell coord modulo
+	#[serde(rename = "yModulo")]
+	pub y_modulo: i64,
+
+	/// Y cell start offset
+	#[serde(rename = "yOffset")]
+	pub y_offset: i64,
+}
+
+/// IntGrid value definition
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct IntGridValueDefinition {
+	#[serde(rename = "color")]
+	pub color: String,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: Option<String>,
+
+	/// The IntGrid value itself
+	#[serde(rename = "value")]
+	pub value: i64,
+}
+
+/// The `Tileset` definition is the most important part among project definitions. It
+/// contains some extra informations about each integrated tileset. If you only had to parse
+/// one definition section, that would be the one.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TilesetDefinition {
+	/// Grid-based height
+	#[serde(rename = "__cHei")]
+	pub c_hei: i64,
+
+	/// Grid-based width
+	#[serde(rename = "__cWid")]
+	pub c_wid: i64,
+
+	/// The following data is used internally for various optimizations. It's always synced with
+	/// source image changes.
+	#[serde(rename = "cachedPixelData")]
+	pub cached_pixel_data: Option<HashMap<String, Option<serde_json::Value>>>,
+
+	/// An array of custom tile metadata
+	#[serde(rename = "customData")]
+	pub custom_data: Vec<TileCustomMetadata>,
+
+	/// If this value is set, then it means that this atlas uses an internal LDtk atlas image
+	/// instead of a loaded one. Possible values: &lt;`null`&gt;, `LdtkIcons`
+	#[serde(rename = "embedAtlas")]
+	pub embed_atlas: Option<EmbedAtlas>,
+
+	/// Tileset tags using Enum values specified by `tagsSourceEnumId`. This array contains 1
+	/// element per Enum value, which contains an array of all Tile IDs that are tagged with it.
+	#[serde(rename = "enumTags")]
+	pub enum_tags: Vec<EnumTagValue>,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Distance in pixels from image borders
+	#[serde(rename = "padding")]
+	pub padding: i64,
+
+	/// Image height in pixels
+	#[serde(rename = "pxHei")]
+	pub px_hei: i64,
+
+	/// Image width in pixels
+	#[serde(rename = "pxWid")]
+	pub px_wid: i64,
+
+	/// Path to the source file, relative to the current project JSON file<br/>  It can be null
+	/// if no image was provided, or when using an embed atlas.
+	#[serde(rename = "relPath")]
+	pub rel_path: Option<String>,
+
+	/// Array of group of tiles selections, only meant to be used in the editor
+	#[serde(rename = "savedSelections")]
+	pub saved_selections: Vec<HashMap<String, Option<serde_json::Value>>>,
+
+	/// Space in pixels between all tiles
+	#[serde(rename = "spacing")]
+	pub spacing: i64,
+
+	/// An array of user-defined tags to organize the Tilesets
+	#[serde(rename = "tags")]
+	pub tags: Vec<String>,
+
+	/// Optional Enum definition UID used for this tileset meta-data
+	#[serde(rename = "tagsSourceEnumUid")]
+	pub tags_source_enum_uid: Option<i64>,
+
+	#[serde(rename = "tileGridSize")]
+	pub tile_grid_size: i64,
+
+	/// Unique Intidentifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+}
+
+/// In a tileset definition, user defined meta-data of a tile.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TileCustomMetadata {
+	#[serde(rename = "data")]
+	pub data: String,
+
+	#[serde(rename = "tileId")]
+	pub tile_id: i64,
+}
+
+/// In a tileset definition, enum based tag infos
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EnumTagValue {
+	#[serde(rename = "enumValueId")]
+	pub enum_value_id: String,
+
+	#[serde(rename = "tileIds")]
+	pub tile_ids: Vec<i64>,
+}
+
+/// This object is not actually used by LDtk. It ONLY exists to force explicit references to
+/// all types, to make sure QuickType finds them and integrate all of them. Otherwise,
+/// Quicktype will drop types that are not explicitely used.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ForcedRefs {
+	#[serde(rename = "AutoLayerRuleGroup")]
+	pub auto_layer_rule_group: Option<AutoLayerRuleGroup>,
+
+	#[serde(rename = "AutoRuleDef")]
+	pub auto_rule_def: Option<AutoLayerRuleDefinition>,
+
+	#[serde(rename = "CustomCommand")]
+	pub custom_command: Option<LdtkCustomCommand>,
+
+	#[serde(rename = "Definitions")]
+	pub definitions: Option<Definitions>,
+
+	#[serde(rename = "EntityDef")]
+	pub entity_def: Option<EntityDefinition>,
+
+	#[serde(rename = "EntityInstance")]
+	pub entity_instance: Option<EntityInstance>,
+
+	#[serde(rename = "EntityReferenceInfos")]
+	pub entity_reference_infos: Option<ReferenceToAnEntityInstance>,
+
+	#[serde(rename = "EnumDef")]
+	pub enum_def: Option<EnumDefinition>,
+
+	#[serde(rename = "EnumDefValues")]
+	pub enum_def_values: Option<EnumValueDefinition>,
+
+	#[serde(rename = "EnumTagValue")]
+	pub enum_tag_value: Option<EnumTagValue>,
+
+	#[serde(rename = "FieldDef")]
+	pub field_def: Option<FieldDefinition>,
+
+	#[serde(rename = "FieldInstance")]
+	pub field_instance: Option<FieldInstance>,
+
+	#[serde(rename = "GridPoint")]
+	pub grid_point: Option<GridPoint>,
+
+	#[serde(rename = "IntGridValueDef")]
+	pub int_grid_value_def: Option<IntGridValueDefinition>,
+
+	#[serde(rename = "IntGridValueInstance")]
+	pub int_grid_value_instance: Option<IntGridValueInstance>,
+
+	#[serde(rename = "LayerDef")]
+	pub layer_def: Option<LayerDefinition>,
+
+	#[serde(rename = "LayerInstance")]
+	pub layer_instance: Option<LayerInstance>,
+
+	#[serde(rename = "Level")]
+	pub level: Option<Level>,
+
+	#[serde(rename = "LevelBgPosInfos")]
+	pub level_bg_pos_infos: Option<LevelBackgroundPosition>,
+
+	#[serde(rename = "NeighbourLevel")]
+	pub neighbour_level: Option<NeighbourLevel>,
+
+	#[serde(rename = "TableOfContentEntry")]
+	pub table_of_content_entry: Option<LdtkTableOfContentEntry>,
+
+	#[serde(rename = "Tile")]
+	pub tile: Option<TileInstance>,
+
+	#[serde(rename = "TileCustomMetadata")]
+	pub tile_custom_metadata: Option<TileCustomMetadata>,
+
+	#[serde(rename = "TilesetDef")]
+	pub tileset_def: Option<TilesetDefinition>,
+
+	#[serde(rename = "TilesetRect")]
+	pub tileset_rect: Option<TilesetRectangle>,
+
+	#[serde(rename = "World")]
+	pub world: Option<World>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EntityInstance {
+	/// Grid-based coordinates (`[x,y]` format)
+	#[serde(rename = "__grid")]
+	pub grid: Vec<i64>,
+
+	/// Entity definition identifier
+	#[serde(rename = "__identifier")]
+	pub identifier: String,
+
+	/// Pivot coordinates  (`[x,y]` format, values are from 0 to 1) of the Entity
+	#[serde(rename = "__pivot")]
+	pub pivot: Vec<f64>,
+
+	/// The entity "smart" color, guessed from either Entity definition, or one its field
+	/// instances.
+	#[serde(rename = "__smartColor")]
+	pub smart_color: String,
+
+	/// Array of tags defined in this Entity definition
+	#[serde(rename = "__tags")]
+	pub tags: Vec<String>,
+
+	/// Optional TilesetRect used to display this entity (it could either be the default Entity
+	/// tile, or some tile provided by a field value, like an Enum).
+	#[serde(rename = "__tile")]
+	pub tile: Option<TilesetRectangle>,
+
+	/// Reference of the **Entity definition** UID
+	#[serde(rename = "defUid")]
+	pub def_uid: i64,
+
+	/// An array of all custom fields and their values.
+	#[serde(rename = "fieldInstances")]
+	pub field_instances: Vec<FieldInstance>,
+
+	/// Entity height in pixels. For non-resizable entities, it will be the same as Entity
+	/// definition.
+	#[serde(rename = "height")]
+	pub height: i64,
+
+	/// Unique instance identifier
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// Pixel coordinates (`[x,y]` format) in current level coordinate space. Don't forget
+	/// optional layer offsets, if they exist!
+	#[serde(rename = "px")]
+	pub px: Vec<i64>,
+
+	/// Entity width in pixels. For non-resizable entities, it will be the same as Entity
+	/// definition.
+	#[serde(rename = "width")]
+	pub width: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct FieldInstance {
+	/// Field definition identifier
+	#[serde(rename = "__identifier")]
+	pub identifier: String,
+
+	/// Optional TilesetRect used to display this field (this can be the field own Tile, or some
+	/// other Tile guessed from the value, like an Enum).
+	#[serde(rename = "__tile")]
+	pub tile: Option<TilesetRectangle>,
+
+	/// Type of the field, such as `Int`, `Float`, `String`, `Enum(my_enum_name)`, `Bool`,
+	/// etc.<br/>  NOTE: if you enable the advanced option **Use Multilines type**, you will have
+	/// "*Multilines*" instead of "*String*" when relevant.
+	#[serde(rename = "__type")]
+	pub field_instance_type: String,
+
+	/// Actual value of the field instance. The value type varies, depending on `__type`:<br/>
+	/// - For **classic types** (ie. Integer, Float, Boolean, String, Text and FilePath), you
+	/// just get the actual value with the expected type.<br/>   - For **Color**, the value is an
+	/// hexadecimal string using "#rrggbb" format.<br/>   - For **Enum**, the value is a String
+	/// representing the selected enum value.<br/>   - For **Point**, the value is a
+	/// [GridPoint](#ldtk-GridPoint) object.<br/>   - For **Tile**, the value is a
+	/// [TilesetRect](#ldtk-TilesetRect) object.<br/>   - For **EntityRef**, the value is an
+	/// [EntityReferenceInfos](#ldtk-EntityReferenceInfos) object.<br/><br/>  If the field is an
+	/// array, then this `__value` will also be a JSON array.
+	#[serde(rename = "__value")]
+	pub value: Option<serde_json::Value>,
+
+	/// Reference of the **Field definition** UID
+	#[serde(rename = "defUid")]
+	pub def_uid: i64,
+
+	/// Editor internal raw values
+	#[serde(rename = "realEditorValues")]
+	pub real_editor_values: Vec<Option<serde_json::Value>>,
+}
+
+/// This object describes the "location" of an Entity instance in the project worlds.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ReferenceToAnEntityInstance {
+	/// IID of the refered EntityInstance
+	#[serde(rename = "entityIid")]
+	pub entity_iid: String,
+
+	/// IID of the LayerInstance containing the refered EntityInstance
+	#[serde(rename = "layerIid")]
+	pub layer_iid: String,
+
+	/// IID of the Level containing the refered EntityInstance
+	#[serde(rename = "levelIid")]
+	pub level_iid: String,
+
+	/// IID of the World containing the refered EntityInstance
+	#[serde(rename = "worldIid")]
+	pub world_iid: String,
+}
+
+/// This object is just a grid-based coordinate used in Field values.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct GridPoint {
+	/// X grid-based coordinate
+	#[serde(rename = "cx")]
+	pub cx: i64,
+
+	/// Y grid-based coordinate
+	#[serde(rename = "cy")]
+	pub cy: i64,
+}
+
+/// IntGrid value instance
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct IntGridValueInstance {
+	/// Coordinate ID in the layer grid
+	#[serde(rename = "coordId")]
+	pub coord_id: i64,
+
+	/// IntGrid value
+	#[serde(rename = "v")]
+	pub v: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LayerInstance {
+	/// Grid-based height
+	#[serde(rename = "__cHei")]
+	pub c_hei: i64,
+
+	/// Grid-based width
+	#[serde(rename = "__cWid")]
+	pub c_wid: i64,
+
+	/// Grid size
+	#[serde(rename = "__gridSize")]
+	pub grid_size: i64,
+
+	/// Layer definition identifier
+	#[serde(rename = "__identifier")]
+	pub identifier: String,
+
+	/// Layer opacity as Float [0-1]
+	#[serde(rename = "__opacity")]
+	pub opacity: f64,
+
+	/// Total layer X pixel offset, including both instance and definition offsets.
+	#[serde(rename = "__pxTotalOffsetX")]
+	pub px_total_offset_x: i64,
+
+	/// Total layer Y pixel offset, including both instance and definition offsets.
+	#[serde(rename = "__pxTotalOffsetY")]
+	pub px_total_offset_y: i64,
+
+	/// The definition UID of corresponding Tileset, if any.
+	#[serde(rename = "__tilesetDefUid")]
+	pub tileset_def_uid: Option<i64>,
+
+	/// The relative path to corresponding Tileset, if any.
+	#[serde(rename = "__tilesetRelPath")]
+	pub tileset_rel_path: Option<String>,
+
+	/// Layer type (possible values: IntGrid, Entities, Tiles or AutoLayer)
+	#[serde(rename = "__type")]
+	pub layer_instance_type: String,
+
+	/// An array containing all tiles generated by Auto-layer rules. The array is already sorted
+	/// in display order (ie. 1st tile is beneath 2nd, which is beneath 3rd etc.).<br/><br/>
+	/// Note: if multiple tiles are stacked in the same cell as the result of different rules,
+	/// all tiles behind opaque ones will be discarded.
+	#[serde(rename = "autoLayerTiles")]
+	pub auto_layer_tiles: Vec<TileInstance>,
+
+	#[serde(rename = "entityInstances")]
+	pub entity_instances: Vec<EntityInstance>,
+
+	#[serde(rename = "gridTiles")]
+	pub grid_tiles: Vec<TileInstance>,
+
+	/// Unique layer instance identifier
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 1.0.0  Replaced
+	/// by: `intGridCsv`
+	#[serde(rename = "intGrid")]
+	pub int_grid: Option<Vec<IntGridValueInstance>>,
+
+	/// A list of all values in the IntGrid layer, stored in CSV format (Comma Separated
+	/// Values).<br/>  Order is from left to right, and top to bottom (ie. first row from left to
+	/// right, followed by second row, etc).<br/>  `0` means "empty cell" and IntGrid values
+	/// start at 1.<br/>  The array size is `__cWid` x `__cHei` cells.
+	#[serde(rename = "intGridCsv")]
+	pub int_grid_csv: Vec<i64>,
+
+	/// Reference the Layer definition UID
+	#[serde(rename = "layerDefUid")]
+	pub layer_def_uid: i64,
+
+	/// Reference to the UID of the level containing this layer instance
+	#[serde(rename = "levelId")]
+	pub level_id: i64,
+
+	/// An Array containing the UIDs of optional rules that were enabled in this specific layer
+	/// instance.
+	#[serde(rename = "optionalRules")]
+	pub optional_rules: Vec<i64>,
+
+	/// This layer can use another tileset by overriding the tileset UID here.
+	#[serde(rename = "overrideTilesetUid")]
+	pub override_tileset_uid: Option<i64>,
+
+	/// X offset in pixels to render this layer, usually 0 (IMPORTANT: this should be added to
+	/// the `LayerDef` optional offset, so you should probably prefer using `__pxTotalOffsetX`
+	/// which contains the total offset value)
+	#[serde(rename = "pxOffsetX")]
+	pub px_offset_x: i64,
+
+	/// Y offset in pixels to render this layer, usually 0 (IMPORTANT: this should be added to
+	/// the `LayerDef` optional offset, so you should probably prefer using `__pxTotalOffsetX`
+	/// which contains the total offset value)
+	#[serde(rename = "pxOffsetY")]
+	pub px_offset_y: i64,
+
+	/// Random seed used for Auto-Layers rendering
+	#[serde(rename = "seed")]
+	pub seed: i64,
+
+	/// Layer instance visibility
+	#[serde(rename = "visible")]
+	pub visible: bool,
+}
+
+/// This structure represents a single tile from a given Tileset.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TileInstance {
+	/// Internal data used by the editor.<br/>  For auto-layer tiles: `[ruleId, coordId]`.<br/>
+	/// For tile-layer tiles: `[coordId]`.
+	#[serde(rename = "d")]
+	pub d: Vec<i64>,
+
+	/// "Flip bits", a 2-bits integer to represent the mirror transformations of the tile.<br/>
+	/// - Bit 0 = X flip<br/>   - Bit 1 = Y flip<br/>   Examples: f=0 (no flip), f=1 (X flip
+	/// only), f=2 (Y flip only), f=3 (both flips)
+	#[serde(rename = "f")]
+	pub f: i64,
+
+	/// Pixel coordinates of the tile in the **layer** (`[x,y]` format). Don't forget optional
+	/// layer offsets, if they exist!
+	#[serde(rename = "px")]
+	pub px: Vec<i64>,
+
+	/// Pixel coordinates of the tile in the **tileset** (`[x,y]` format)
+	#[serde(rename = "src")]
+	pub src: Vec<i64>,
+
+	/// The *Tile ID* in the corresponding tileset.
+	#[serde(rename = "t")]
+	pub t: i64,
+}
+
+/// This section contains all the level data. It can be found in 2 distinct forms, depending
+/// on Project current settings:  - If "*Separate level files*" is **disabled** (default):
+/// full level data is *embedded* inside the main Project JSON file, - If "*Separate level
+/// files*" is **enabled**: level data is stored in *separate* standalone `.ldtkl` files (one
+/// per level). In this case, the main Project JSON file will still contain most level data,
+/// except heavy sections, like the `layerInstances` array (which will be null). The
+/// `externalRelPath` string points to the `ldtkl` file.  A `ldtkl` file is just a JSON file
+/// containing exactly what is described below.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Level {
+	/// Background color of the level (same as `bgColor`, except the default value is
+	/// automatically used here if its value is `null`)
+	#[serde(rename = "__bgColor")]
+	pub bg_color: String,
+
+	/// Position informations of the background image, if there is one.
+	#[serde(rename = "__bgPos")]
+	pub bg_pos: Option<LevelBackgroundPosition>,
+
+	/// An array listing all other levels touching this one on the world map.<br/>  Only relevant
+	/// for world layouts where level spatial positioning is manual (ie. GridVania, Free). For
+	/// Horizontal and Vertical layouts, this array is always empty.
+	#[serde(rename = "__neighbours")]
+	pub neighbours: Vec<NeighbourLevel>,
+
+	/// The "guessed" color for this level in the editor, decided using either the background
+	/// color or an existing custom field.
+	#[serde(rename = "__smartColor")]
+	pub smart_color: String,
+
+	/// Background color of the level. If `null`, the project `defaultLevelBgColor` should be
+	/// used.
+	#[serde(rename = "bgColor")]
+	pub level_bg_color: Option<String>,
+
+	/// Background image X pivot (0-1)
+	#[serde(rename = "bgPivotX")]
+	pub bg_pivot_x: f64,
+
+	/// Background image Y pivot (0-1)
+	#[serde(rename = "bgPivotY")]
+	pub bg_pivot_y: f64,
+
+	/// An enum defining the way the background image (if any) is positioned on the level. See
+	/// `__bgPos` for resulting position info. Possible values: &lt;`null`&gt;, `Unscaled`,
+	/// `Contain`, `Cover`, `CoverDirty`
+	#[serde(rename = "bgPos")]
+	pub level_bg_pos: Option<BgPos>,
+
+	/// The *optional* relative path to the level background image.
+	#[serde(rename = "bgRelPath")]
+	pub bg_rel_path: Option<String>,
+
+	/// This value is not null if the project option "*Save levels separately*" is enabled. In
+	/// this case, this **relative** path points to the level Json file.
+	#[serde(rename = "externalRelPath")]
+	pub external_rel_path: Option<String>,
+
+	/// An array containing this level custom field values.
+	#[serde(rename = "fieldInstances")]
+	pub field_instances: Vec<FieldInstance>,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Unique instance identifier
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// An array containing all Layer instances. **IMPORTANT**: if the project option "*Save
+	/// levels separately*" is enabled, this field will be `null`.<br/>  This array is **sorted
+	/// in display order**: the 1st layer is the top-most and the last is behind.
+	#[serde(rename = "layerInstances")]
+	pub layer_instances: Option<Vec<LayerInstance>>,
+
+	/// Height of the level in pixels
+	#[serde(rename = "pxHei")]
+	pub px_hei: i64,
+
+	/// Width of the level in pixels
+	#[serde(rename = "pxWid")]
+	pub px_wid: i64,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// If TRUE, the level identifier will always automatically use the naming pattern as defined
+	/// in `Project.levelNamePattern`. Becomes FALSE if the identifier is manually modified by
+	/// user.
+	#[serde(rename = "useAutoIdentifier")]
+	pub use_auto_identifier: bool,
+
+	/// Index that represents the "depth" of the level in the world. Default is 0, greater means
+	/// "above", lower means "below".<br/>  This value is mostly used for display only and is
+	/// intended to make stacking of levels easier to manage.
+	#[serde(rename = "worldDepth")]
+	pub world_depth: i64,
+
+	/// World X coordinate in pixels.<br/>  Only relevant for world layouts where level spatial
+	/// positioning is manual (ie. GridVania, Free). For Horizontal and Vertical layouts, the
+	/// value is always -1 here.
+	#[serde(rename = "worldX")]
+	pub world_x: i64,
+
+	/// World Y coordinate in pixels.<br/>  Only relevant for world layouts where level spatial
+	/// positioning is manual (ie. GridVania, Free). For Horizontal and Vertical layouts, the
+	/// value is always -1 here.
+	#[serde(rename = "worldY")]
+	pub world_y: i64,
+}
+
+/// Level background image position info
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LevelBackgroundPosition {
+	/// An array of 4 float values describing the cropped sub-rectangle of the displayed
+	/// background image. This cropping happens when original is larger than the level bounds.
+	/// Array format: `[ cropX, cropY, cropWidth, cropHeight ]`
+	#[serde(rename = "cropRect")]
+	pub crop_rect: Vec<f64>,
+
+	/// An array containing the `[scaleX,scaleY]` values of the **cropped** background image,
+	/// depending on `bgPos` option.
+	#[serde(rename = "scale")]
+	pub scale: Vec<f64>,
+
+	/// An array containing the `[x,y]` pixel coordinates of the top-left corner of the
+	/// **cropped** background image, depending on `bgPos` option.
+	#[serde(rename = "topLeftPx")]
+	pub top_left_px: Vec<i64>,
+}
+
+/// Nearby level info
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct NeighbourLevel {
+	/// A single lowercase character tipping on the level location (`n`orth, `s`outh, `w`est,
+	/// `e`ast).
+	#[serde(rename = "dir")]
+	pub dir: String,
+
+	/// Neighbour Instance Identifier
+	#[serde(rename = "levelIid")]
+	pub level_iid: String,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 1.2.0  Replaced
+	/// by: `levelIid`
+	#[serde(rename = "levelUid")]
+	pub level_uid: Option<i64>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LdtkTableOfContentEntry {
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	#[serde(rename = "instances")]
+	pub instances: Vec<ReferenceToAnEntityInstance>,
+}
+
+/// **IMPORTANT**: this type is not used *yet* in current LDtk version. It's only presented
+/// here as a preview of a planned feature.  A World contains multiple levels, and it has its
+/// own layout settings.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct World {
+	/// Default new level height
+	#[serde(rename = "defaultLevelHeight")]
+	pub default_level_height: i64,
+
+	/// Default new level width
+	#[serde(rename = "defaultLevelWidth")]
+	pub default_level_width: i64,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Unique instance identifer
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// All levels from this world. The order of this array is only relevant in
+	/// `LinearHorizontal` and `linearVertical` world layouts (see `worldLayout` value).
+	/// Otherwise, you should refer to the `worldX`,`worldY` coordinates of each Level.
+	#[serde(rename = "levels")]
+	pub levels: Vec<Level>,
+
+	/// Height of the world grid in pixels.
+	#[serde(rename = "worldGridHeight")]
+	pub world_grid_height: i64,
+
+	/// Width of the world grid in pixels.
+	#[serde(rename = "worldGridWidth")]
+	pub world_grid_width: i64,
+
+	/// An enum that describes how levels are organized in this project (ie. linearly or in a 2D
+	/// space). Possible values: `Free`, `GridVania`, `LinearHorizontal`, `LinearVertical`, `null`
+	#[serde(rename = "worldLayout")]
+	pub world_layout: Option<WorldLayout>,
+}
+
+/// Possible values: `Manual`, `AfterLoad`, `BeforeSave`, `AfterSave`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum When {
+	#[serde(rename = "AfterLoad")]
+	AfterLoad,
+
+	#[serde(rename = "AfterSave")]
+	AfterSave,
+
+	#[serde(rename = "BeforeSave")]
+	BeforeSave,
+
+	#[serde(rename = "Manual")]
+	Manual,
+}
+
+/// Possible values: `Any`, `OnlySame`, `OnlyTags`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum AllowedRefs {
+	#[serde(rename = "Any")]
+	Any,
+
+	#[serde(rename = "OnlySame")]
+	OnlySame,
+
+	#[serde(rename = "OnlyTags")]
+	OnlyTags,
+}
+
+/// Possible values: `Hidden`, `ValueOnly`, `NameAndValue`, `EntityTile`, `Points`,
+/// `PointStar`, `PointPath`, `PointPathLoop`, `RadiusPx`, `RadiusGrid`,
+/// `ArrayCountWithLabel`, `ArrayCountNoLabel`, `RefLinkBetweenPivots`,
+/// `RefLinkBetweenCenters`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum EditorDisplayMode {
+	#[serde(rename = "ArrayCountNoLabel")]
+	ArrayCountNoLabel,
+
+	#[serde(rename = "ArrayCountWithLabel")]
+	ArrayCountWithLabel,
+
+	#[serde(rename = "EntityTile")]
+	EntityTile,
+
+	#[serde(rename = "Hidden")]
+	Hidden,
+
+	#[serde(rename = "NameAndValue")]
+	NameAndValue,
+
+	#[serde(rename = "PointPath")]
+	PointPath,
+
+	#[serde(rename = "PointPathLoop")]
+	PointPathLoop,
+
+	#[serde(rename = "PointStar")]
+	PointStar,
+
+	#[serde(rename = "Points")]
+	Points,
+
+	#[serde(rename = "RadiusGrid")]
+	RadiusGrid,
+
+	#[serde(rename = "RadiusPx")]
+	RadiusPx,
+
+	#[serde(rename = "RefLinkBetweenCenters")]
+	RefLinkBetweenCenters,
+
+	#[serde(rename = "RefLinkBetweenPivots")]
+	RefLinkBetweenPivots,
+
+	#[serde(rename = "ValueOnly")]
+	ValueOnly,
+}
+
+/// Possible values: `Above`, `Center`, `Beneath`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum EditorDisplayPos {
+	#[serde(rename = "Above")]
+	Above,
+
+	#[serde(rename = "Beneath")]
+	Beneath,
+
+	#[serde(rename = "Center")]
+	Center,
+}
+
+/// Possible values: `ZigZag`, `StraightArrow`, `CurvedArrow`, `ArrowsLine`, `DashedLine`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum EditorLinkStyle {
+	#[serde(rename = "ArrowsLine")]
+	ArrowsLine,
+
+	#[serde(rename = "CurvedArrow")]
+	CurvedArrow,
+
+	#[serde(rename = "DashedLine")]
+	DashedLine,
+
+	#[serde(rename = "StraightArrow")]
+	StraightArrow,
+
+	#[serde(rename = "ZigZag")]
+	ZigZag,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum TextLanguageMode {
+	#[serde(rename = "LangC")]
+	LangC,
+
+	#[serde(rename = "LangHaxe")]
+	LangHaxe,
+
+	#[serde(rename = "LangJS")]
+	LangJs,
+
+	#[serde(rename = "LangJson")]
+	LangJson,
+
+	#[serde(rename = "LangLog")]
+	LangLog,
+
+	#[serde(rename = "LangLua")]
+	LangLua,
+
+	#[serde(rename = "LangMarkdown")]
+	LangMarkdown,
+
+	#[serde(rename = "LangPython")]
+	LangPython,
+
+	#[serde(rename = "LangRuby")]
+	LangRuby,
+
+	#[serde(rename = "LangXml")]
+	LangXml,
+}
+
+/// Possible values: `DiscardOldOnes`, `PreventAdding`, `MoveLastOne`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum LimitBehavior {
+	#[serde(rename = "DiscardOldOnes")]
+	DiscardOldOnes,
+
+	#[serde(rename = "MoveLastOne")]
+	MoveLastOne,
+
+	#[serde(rename = "PreventAdding")]
+	PreventAdding,
+}
+
+/// If TRUE, the maxCount is a "per world" limit, if FALSE, it's a "per level". Possible
+/// values: `PerLayer`, `PerLevel`, `PerWorld`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum LimitScope {
+	#[serde(rename = "PerLayer")]
+	PerLayer,
+
+	#[serde(rename = "PerLevel")]
+	PerLevel,
+
+	#[serde(rename = "PerWorld")]
+	PerWorld,
+}
+
+/// Possible values: `Rectangle`, `Ellipse`, `Tile`, `Cross`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum RenderMode {
+	#[serde(rename = "Cross")]
+	Cross,
+
+	#[serde(rename = "Ellipse")]
+	Ellipse,
+
+	#[serde(rename = "Rectangle")]
+	Rectangle,
+
+	#[serde(rename = "Tile")]
+	Tile,
+}
+
+/// An enum describing how the the Entity tile is rendered inside the Entity bounds. Possible
+/// values: `Cover`, `FitInside`, `Repeat`, `Stretch`, `FullSizeCropped`,
+/// `FullSizeUncropped`, `NineSlice`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum TileRenderMode {
+	#[serde(rename = "Cover")]
+	Cover,
+
+	#[serde(rename = "FitInside")]
+	FitInside,
+
+	#[serde(rename = "FullSizeCropped")]
+	FullSizeCropped,
+
+	#[serde(rename = "FullSizeUncropped")]
+	FullSizeUncropped,
+
+	#[serde(rename = "NineSlice")]
+	NineSlice,
+
+	#[serde(rename = "Repeat")]
+	Repeat,
+
+	#[serde(rename = "Stretch")]
+	Stretch,
+}
+
+/// Checker mode Possible values: `None`, `Horizontal`, `Vertical`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Checker {
+	#[serde(rename = "Horizontal")]
+	Horizontal,
+
+	#[serde(rename = "None")]
+	None,
+
+	#[serde(rename = "Vertical")]
+	Vertical,
+}
+
+/// Defines how tileIds array is used Possible values: `Single`, `Stamp`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum TileMode {
+	#[serde(rename = "Single")]
+	Single,
+
+	#[serde(rename = "Stamp")]
+	Stamp,
+}
+
+/// Type of the layer as Haxe Enum Possible values: `IntGrid`, `Entities`, `Tiles`,
+/// `AutoLayer`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Type {
+	#[serde(rename = "AutoLayer")]
+	AutoLayer,
+
+	#[serde(rename = "Entities")]
+	Entities,
+
+	#[serde(rename = "IntGrid")]
+	IntGrid,
+
+	#[serde(rename = "Tiles")]
+	Tiles,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum EmbedAtlas {
+	#[serde(rename = "LdtkIcons")]
+	LdtkIcons,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Flag {
+	#[serde(rename = "DiscardPreCsvIntGrid")]
+	DiscardPreCsvIntGrid,
+
+	#[serde(rename = "ExportPreCsvIntGridFormat")]
+	ExportPreCsvIntGridFormat,
+
+	#[serde(rename = "IgnoreBackupSuggest")]
+	IgnoreBackupSuggest,
+
+	#[serde(rename = "MultiWorlds")]
+	MultiWorlds,
+
+	#[serde(rename = "PrependIndexToLevelFileNames")]
+	PrependIndexToLevelFileNames,
+
+	#[serde(rename = "UseMultilinesType")]
+	UseMultilinesType,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum BgPos {
+	#[serde(rename = "Contain")]
+	Contain,
+
+	#[serde(rename = "Cover")]
+	Cover,
+
+	#[serde(rename = "CoverDirty")]
+	CoverDirty,
+
+	#[serde(rename = "Unscaled")]
+	Unscaled,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum WorldLayout {
+	#[serde(rename = "Free")]
+	Free,
+
+	#[serde(rename = "GridVania")]
+	GridVania,
+
+	#[serde(rename = "LinearHorizontal")]
+	LinearHorizontal,
+
+	#[serde(rename = "LinearVertical")]
+	LinearVertical,
+}
+
+/// Naming convention for Identifiers (first-letter uppercase, full uppercase etc.) Possible
+/// values: `Capitalize`, `Uppercase`, `Lowercase`, `Free`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum IdentifierStyle {
+	#[serde(rename = "Capitalize")]
+	Capitalize,
+
+	#[serde(rename = "Free")]
+	Free,
+
+	#[serde(rename = "Lowercase")]
+	Lowercase,
+
+	#[serde(rename = "Uppercase")]
+	Uppercase,
+}
+
+/// "Image export" option when saving project. Possible values: `None`, `OneImagePerLayer`,
+/// `OneImagePerLevel`, `LayersAndLevels`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum ImageExportMode {
+	#[serde(rename = "LayersAndLevels")]
+	LayersAndLevels,
+
+	#[serde(rename = "None")]
+	None,
+
+	#[serde(rename = "OneImagePerLayer")]
+	OneImagePerLayer,
+
+	#[serde(rename = "OneImagePerLevel")]
+	OneImagePerLevel,
+}
diff --git a/src/ldtk/data_1_2_5.rs b/src/ldtk/data_1_2_5.rs
new file mode 100644
index 0000000000000000000000000000000000000000..54cb1786f001d8aa8484648d0563dafc54d73dcf
--- /dev/null
+++ b/src/ldtk/data_1_2_5.rs
@@ -0,0 +1,1826 @@
+// Example code that deserializes and serializes the model.
+// extern crate serde;
+// #[macro_use]
+// extern crate serde_derive;
+// extern crate serde_json;
+//
+// use generated_module::Project;
+//
+// fn main() {
+//     let json = r#"{"answer": 42}"#;
+//     let model: Project = serde_json::from_str(&json).unwrap();
+// }
+
+use std::collections::HashMap;
+
+use serde::{Deserialize, Serialize};
+
+/// This file is a JSON schema of files created by LDtk level editor (https://ldtk.io).
+///
+/// This is the root of any Project JSON file. It contains:  - the project settings, - an
+/// array of levels, - a group of definitions (that can probably be safely ignored for most
+/// users).
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Project {
+	/// This object is not actually used by LDtk. It ONLY exists to force explicit references to
+	/// all types, to make sure QuickType finds them and integrate all of them. Otherwise,
+	/// Quicktype will drop types that are not explicitely used.
+	#[serde(rename = "__FORCED_REFS")]
+	pub forced_refs: Option<ForcedRefs>,
+
+	/// LDtk application build identifier.<br/>  This is only used to identify the LDtk version
+	/// that generated this particular project file, which can be useful for specific bug fixing.
+	/// Note that the build identifier is just the date of the release, so it's not unique to
+	/// each user (one single global ID per LDtk public release), and as a result, completely
+	/// anonymous.
+	#[serde(rename = "appBuildId")]
+	pub app_build_id: f64,
+
+	/// Number of backup files to keep, if the `backupOnSave` is TRUE
+	#[serde(rename = "backupLimit")]
+	pub backup_limit: i64,
+
+	/// If TRUE, an extra copy of the project will be created in a sub folder, when saving.
+	#[serde(rename = "backupOnSave")]
+	pub backup_on_save: bool,
+
+	/// Project background color
+	#[serde(rename = "bgColor")]
+	pub bg_color: String,
+
+	/// An array of command lines that can be ran manually by the user
+	#[serde(rename = "customCommands")]
+	pub custom_commands: Vec<LdtkCustomCommand>,
+
+	/// Default grid size for new layers
+	#[serde(rename = "defaultGridSize")]
+	pub default_grid_size: i64,
+
+	/// Default background color of levels
+	#[serde(rename = "defaultLevelBgColor")]
+	pub default_level_bg_color: String,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  Default new level height
+	#[serde(rename = "defaultLevelHeight")]
+	pub default_level_height: Option<i64>,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  Default new level width
+	#[serde(rename = "defaultLevelWidth")]
+	pub default_level_width: Option<i64>,
+
+	/// Default X pivot (0 to 1) for new entities
+	#[serde(rename = "defaultPivotX")]
+	pub default_pivot_x: f64,
+
+	/// Default Y pivot (0 to 1) for new entities
+	#[serde(rename = "defaultPivotY")]
+	pub default_pivot_y: f64,
+
+	/// A structure containing all the definitions of this project
+	#[serde(rename = "defs")]
+	pub defs: Definitions,
+
+	/// If TRUE, the exported PNGs will include the level background (color or image).
+	#[serde(rename = "exportLevelBg")]
+	pub export_level_bg: bool,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 0.9.3  Replaced
+	/// by: `imageExportMode`
+	#[serde(rename = "exportPng")]
+	pub export_png: Option<bool>,
+
+	/// If TRUE, a Tiled compatible file will also be generated along with the LDtk JSON file
+	/// (default is FALSE)
+	#[serde(rename = "exportTiled")]
+	pub export_tiled: bool,
+
+	/// If TRUE, one file will be saved for the project (incl. all its definitions) and one file
+	/// in a sub-folder for each level.
+	#[serde(rename = "externalLevels")]
+	pub external_levels: bool,
+
+	/// An array containing various advanced flags (ie. options or other states). Possible
+	/// values: `DiscardPreCsvIntGrid`, `ExportPreCsvIntGridFormat`, `IgnoreBackupSuggest`,
+	/// `PrependIndexToLevelFileNames`, `MultiWorlds`, `UseMultilinesType`
+	#[serde(rename = "flags")]
+	pub flags: Vec<Flag>,
+
+	/// Naming convention for Identifiers (first-letter uppercase, full uppercase etc.) Possible
+	/// values: `Capitalize`, `Uppercase`, `Lowercase`, `Free`
+	#[serde(rename = "identifierStyle")]
+	pub identifier_style: IdentifierStyle,
+
+	/// Unique project identifier
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// "Image export" option when saving project. Possible values: `None`, `OneImagePerLayer`,
+	/// `OneImagePerLevel`, `LayersAndLevels`
+	#[serde(rename = "imageExportMode")]
+	pub image_export_mode: ImageExportMode,
+
+	/// File format version
+	#[serde(rename = "jsonVersion")]
+	pub json_version: String,
+
+	/// The default naming convention for level identifiers.
+	#[serde(rename = "levelNamePattern")]
+	pub level_name_pattern: String,
+
+	/// All levels. The order of this array is only relevant in `LinearHorizontal` and
+	/// `linearVertical` world layouts (see `worldLayout` value).<br/>  Otherwise, you should
+	/// refer to the `worldX`,`worldY` coordinates of each Level.
+	#[serde(rename = "levels")]
+	pub levels: Vec<Level>,
+
+	/// If TRUE, the Json is partially minified (no indentation, nor line breaks, default is
+	/// FALSE)
+	#[serde(rename = "minifyJson")]
+	pub minify_json: bool,
+
+	/// Next Unique integer ID available
+	#[serde(rename = "nextUid")]
+	pub next_uid: i64,
+
+	/// File naming pattern for exported PNGs
+	#[serde(rename = "pngFilePattern")]
+	pub png_file_pattern: Option<String>,
+
+	/// If TRUE, a very simplified will be generated on saving, for quicker & easier engine
+	/// integration.
+	#[serde(rename = "simplifiedExport")]
+	pub simplified_export: bool,
+
+	/// All instances of entities that have their `exportToToc` flag enabled are listed in this
+	/// array.
+	#[serde(rename = "toc")]
+	pub toc: Vec<LdtkTableOfContentEntry>,
+
+	/// This optional description is used by LDtk Samples to show up some informations and
+	/// instructions.
+	#[serde(rename = "tutorialDesc")]
+	pub tutorial_desc: Option<String>,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  Height of the world grid in pixels.
+	#[serde(rename = "worldGridHeight")]
+	pub world_grid_height: Option<i64>,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  Width of the world grid in pixels.
+	#[serde(rename = "worldGridWidth")]
+	pub world_grid_width: Option<i64>,
+
+	/// **WARNING**: this field will move to the `worlds` array after the "multi-worlds" update.
+	/// It will then be `null`. You can enable the Multi-worlds advanced project option to enable
+	/// the change immediately.<br/><br/>  An enum that describes how levels are organized in
+	/// this project (ie. linearly or in a 2D space). Possible values: &lt;`null`&gt;, `Free`,
+	/// `GridVania`, `LinearHorizontal`, `LinearVertical`
+	#[serde(rename = "worldLayout")]
+	pub world_layout: Option<WorldLayout>,
+
+	/// This array is not used yet in current LDtk version (so, for now, it's always
+	/// empty).<br/><br/>In a later update, it will be possible to have multiple Worlds in a
+	/// single project, each containing multiple Levels.<br/><br/>What will change when "Multiple
+	/// worlds" support will be added to LDtk:<br/><br/> - in current version, a LDtk project
+	/// file can only contain a single world with multiple levels in it. In this case, levels and
+	/// world layout related settings are stored in the root of the JSON.<br/> - after the
+	/// "Multiple worlds" update, there will be a `worlds` array in root, each world containing
+	/// levels and layout settings. Basically, it's pretty much only about moving the `levels`
+	/// array to the `worlds` array, along with world layout related values (eg. `worldGridWidth`
+	/// etc).<br/><br/>If you want to start supporting this future update easily, please refer to
+	/// this documentation: https://github.com/deepnight/ldtk/issues/231
+	#[serde(rename = "worlds")]
+	pub worlds: Vec<World>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LdtkCustomCommand {
+	#[serde(rename = "command")]
+	pub command: String,
+
+	/// Possible values: `Manual`, `AfterLoad`, `BeforeSave`, `AfterSave`
+	#[serde(rename = "when")]
+	pub when: When,
+}
+
+/// If you're writing your own LDtk importer, you should probably just ignore *most* stuff in
+/// the `defs` section, as it contains data that are mostly important to the editor. To keep
+/// you away from the `defs` section and avoid some unnecessary JSON parsing, important data
+/// from definitions is often duplicated in fields prefixed with a double underscore (eg.
+/// `__identifier` or `__type`).  The 2 only definition types you might need here are
+/// **Tilesets** and **Enums**.
+///
+/// A structure containing all the definitions of this project
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Definitions {
+	/// All entities definitions, including their custom fields
+	#[serde(rename = "entities")]
+	pub entities: Vec<EntityDefinition>,
+
+	/// All internal enums
+	#[serde(rename = "enums")]
+	pub enums: Vec<EnumDefinition>,
+
+	/// Note: external enums are exactly the same as `enums`, except they have a `relPath` to
+	/// point to an external source file.
+	#[serde(rename = "externalEnums")]
+	pub external_enums: Vec<EnumDefinition>,
+
+	/// All layer definitions
+	#[serde(rename = "layers")]
+	pub layers: Vec<LayerDefinition>,
+
+	/// All custom fields available to all levels.
+	#[serde(rename = "levelFields")]
+	pub level_fields: Vec<FieldDefinition>,
+
+	/// All tilesets
+	#[serde(rename = "tilesets")]
+	pub tilesets: Vec<TilesetDefinition>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EntityDefinition {
+	/// Base entity color
+	#[serde(rename = "color")]
+	pub color: String,
+
+	/// User defined documentation for this element to provide help/tips to level designers.
+	#[serde(rename = "doc")]
+	pub doc: Option<String>,
+
+	/// If enabled, all instances of this entity will be listed in the project "Table of content"
+	/// object.
+	#[serde(rename = "exportToToc")]
+	pub export_to_toc: bool,
+
+	/// Array of field definitions
+	#[serde(rename = "fieldDefs")]
+	pub field_defs: Vec<FieldDefinition>,
+
+	#[serde(rename = "fillOpacity")]
+	pub fill_opacity: f64,
+
+	/// Pixel height
+	#[serde(rename = "height")]
+	pub height: i64,
+
+	#[serde(rename = "hollow")]
+	pub hollow: bool,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Only applies to entities resizable on both X/Y. If TRUE, the entity instance width/height
+	/// will keep the same aspect ratio as the definition.
+	#[serde(rename = "keepAspectRatio")]
+	pub keep_aspect_ratio: bool,
+
+	/// Possible values: `DiscardOldOnes`, `PreventAdding`, `MoveLastOne`
+	#[serde(rename = "limitBehavior")]
+	pub limit_behavior: LimitBehavior,
+
+	/// If TRUE, the maxCount is a "per world" limit, if FALSE, it's a "per level". Possible
+	/// values: `PerLayer`, `PerLevel`, `PerWorld`
+	#[serde(rename = "limitScope")]
+	pub limit_scope: LimitScope,
+
+	#[serde(rename = "lineOpacity")]
+	pub line_opacity: f64,
+
+	/// Max instances count
+	#[serde(rename = "maxCount")]
+	pub max_count: i64,
+
+	/// An array of 4 dimensions for the up/right/down/left borders (in this order) when using
+	/// 9-slice mode for `tileRenderMode`.<br/>  If the tileRenderMode is not NineSlice, then
+	/// this array is empty.<br/>  See: https://en.wikipedia.org/wiki/9-slice_scaling
+	#[serde(rename = "nineSliceBorders")]
+	pub nine_slice_borders: Vec<i64>,
+
+	/// Pivot X coordinate (from 0 to 1.0)
+	#[serde(rename = "pivotX")]
+	pub pivot_x: f64,
+
+	/// Pivot Y coordinate (from 0 to 1.0)
+	#[serde(rename = "pivotY")]
+	pub pivot_y: f64,
+
+	/// Possible values: `Rectangle`, `Ellipse`, `Tile`, `Cross`
+	#[serde(rename = "renderMode")]
+	pub render_mode: RenderMode,
+
+	/// If TRUE, the entity instances will be resizable horizontally
+	#[serde(rename = "resizableX")]
+	pub resizable_x: bool,
+
+	/// If TRUE, the entity instances will be resizable vertically
+	#[serde(rename = "resizableY")]
+	pub resizable_y: bool,
+
+	/// Display entity name in editor
+	#[serde(rename = "showName")]
+	pub show_name: bool,
+
+	/// An array of strings that classifies this entity
+	#[serde(rename = "tags")]
+	pub tags: Vec<String>,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 1.2.0  Replaced
+	/// by: `tileRect`
+	#[serde(rename = "tileId")]
+	pub tile_id: Option<i64>,
+
+	#[serde(rename = "tileOpacity")]
+	pub tile_opacity: f64,
+
+	/// An object representing a rectangle from an existing Tileset
+	#[serde(rename = "tileRect")]
+	pub tile_rect: Option<TilesetRectangle>,
+
+	/// An enum describing how the the Entity tile is rendered inside the Entity bounds. Possible
+	/// values: `Cover`, `FitInside`, `Repeat`, `Stretch`, `FullSizeCropped`,
+	/// `FullSizeUncropped`, `NineSlice`
+	#[serde(rename = "tileRenderMode")]
+	pub tile_render_mode: TileRenderMode,
+
+	/// Tileset ID used for optional tile display
+	#[serde(rename = "tilesetId")]
+	pub tileset_id: Option<i64>,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// Pixel width
+	#[serde(rename = "width")]
+	pub width: i64,
+}
+
+/// This section is mostly only intended for the LDtk editor app itself. You can safely
+/// ignore it.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct FieldDefinition {
+	/// Human readable value type. Possible values: `Int, Float, String, Bool, Color,
+	/// ExternEnum.XXX, LocalEnum.XXX, Point, FilePath`.<br/>  If the field is an array, this
+	/// field will look like `Array<...>` (eg. `Array<Int>`, `Array<Point>` etc.)<br/>  NOTE: if
+	/// you enable the advanced option **Use Multilines type**, you will have "*Multilines*"
+	/// instead of "*String*" when relevant.
+	#[serde(rename = "__type")]
+	pub field_definition_type: String,
+
+	/// Optional list of accepted file extensions for FilePath value type. Includes the dot:
+	/// `.ext`
+	#[serde(rename = "acceptFileTypes")]
+	pub accept_file_types: Option<Vec<String>>,
+
+	/// Possible values: `Any`, `OnlySame`, `OnlyTags`
+	#[serde(rename = "allowedRefs")]
+	pub allowed_refs: AllowedRefs,
+
+	#[serde(rename = "allowedRefTags")]
+	pub allowed_ref_tags: Vec<String>,
+
+	#[serde(rename = "allowOutOfLevelRef")]
+	pub allow_out_of_level_ref: bool,
+
+	/// Array max length
+	#[serde(rename = "arrayMaxLength")]
+	pub array_max_length: Option<i64>,
+
+	/// Array min length
+	#[serde(rename = "arrayMinLength")]
+	pub array_min_length: Option<i64>,
+
+	#[serde(rename = "autoChainRef")]
+	pub auto_chain_ref: bool,
+
+	/// TRUE if the value can be null. For arrays, TRUE means it can contain null values
+	/// (exception: array of Points can't have null values).
+	#[serde(rename = "canBeNull")]
+	pub can_be_null: bool,
+
+	/// Default value if selected value is null or invalid.
+	#[serde(rename = "defaultOverride")]
+	pub default_override: Option<serde_json::Value>,
+
+	/// User defined documentation for this field to provide help/tips to level designers about
+	/// accepted values.
+	#[serde(rename = "doc")]
+	pub doc: Option<String>,
+
+	#[serde(rename = "editorAlwaysShow")]
+	pub editor_always_show: bool,
+
+	#[serde(rename = "editorCutLongValues")]
+	pub editor_cut_long_values: bool,
+
+	/// Possible values: `Hidden`, `ValueOnly`, `NameAndValue`, `EntityTile`, `Points`,
+	/// `PointStar`, `PointPath`, `PointPathLoop`, `RadiusPx`, `RadiusGrid`,
+	/// `ArrayCountWithLabel`, `ArrayCountNoLabel`, `RefLinkBetweenPivots`,
+	/// `RefLinkBetweenCenters`
+	#[serde(rename = "editorDisplayMode")]
+	pub editor_display_mode: EditorDisplayMode,
+
+	/// Possible values: `Above`, `Center`, `Beneath`
+	#[serde(rename = "editorDisplayPos")]
+	pub editor_display_pos: EditorDisplayPos,
+
+	/// Possible values: `ZigZag`, `StraightArrow`, `CurvedArrow`, `ArrowsLine`, `DashedLine`
+	#[serde(rename = "editorLinkStyle")]
+	pub editor_link_style: EditorLinkStyle,
+
+	#[serde(rename = "editorShowInWorld")]
+	pub editor_show_in_world: bool,
+
+	#[serde(rename = "editorTextPrefix")]
+	pub editor_text_prefix: Option<String>,
+
+	#[serde(rename = "editorTextSuffix")]
+	pub editor_text_suffix: Option<String>,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// TRUE if the value is an array of multiple values
+	#[serde(rename = "isArray")]
+	pub is_array: bool,
+
+	/// Max limit for value, if applicable
+	#[serde(rename = "max")]
+	pub max: Option<f64>,
+
+	/// Min limit for value, if applicable
+	#[serde(rename = "min")]
+	pub min: Option<f64>,
+
+	/// Optional regular expression that needs to be matched to accept values. Expected format:
+	/// `/some_reg_ex/g`, with optional "i" flag.
+	#[serde(rename = "regex")]
+	pub regex: Option<String>,
+
+	#[serde(rename = "symmetricalRef")]
+	pub symmetrical_ref: bool,
+
+	/// Possible values: &lt;`null`&gt;, `LangPython`, `LangRuby`, `LangJS`, `LangLua`, `LangC`,
+	/// `LangHaxe`, `LangMarkdown`, `LangJson`, `LangXml`, `LangLog`
+	#[serde(rename = "textLanguageMode")]
+	pub text_language_mode: Option<TextLanguageMode>,
+
+	/// UID of the tileset used for a Tile
+	#[serde(rename = "tilesetUid")]
+	pub tileset_uid: Option<i64>,
+
+	/// Internal enum representing the possible field types. Possible values: F_Int, F_Float,
+	/// F_String, F_Text, F_Bool, F_Color, F_Enum(...), F_Point, F_Path, F_EntityRef, F_Tile
+	#[serde(rename = "type")]
+	pub purple_type: String,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// If TRUE, the color associated with this field will override the Entity or Level default
+	/// color in the editor UI. For Enum fields, this would be the color associated to their
+	/// values.
+	#[serde(rename = "useForSmartColor")]
+	pub use_for_smart_color: bool,
+}
+
+/// This object represents a custom sub rectangle in a Tileset image.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TilesetRectangle {
+	/// Height in pixels
+	#[serde(rename = "h")]
+	pub h: i64,
+
+	/// UID of the tileset
+	#[serde(rename = "tilesetUid")]
+	pub tileset_uid: i64,
+
+	/// Width in pixels
+	#[serde(rename = "w")]
+	pub w: i64,
+
+	/// X pixels coordinate of the top-left corner in the Tileset image
+	#[serde(rename = "x")]
+	pub x: i64,
+
+	/// Y pixels coordinate of the top-left corner in the Tileset image
+	#[serde(rename = "y")]
+	pub y: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EnumDefinition {
+	#[serde(rename = "externalFileChecksum")]
+	pub external_file_checksum: Option<String>,
+
+	/// Relative path to the external file providing this Enum
+	#[serde(rename = "externalRelPath")]
+	pub external_rel_path: Option<String>,
+
+	/// Tileset UID if provided
+	#[serde(rename = "iconTilesetUid")]
+	pub icon_tileset_uid: Option<i64>,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// An array of user-defined tags to organize the Enums
+	#[serde(rename = "tags")]
+	pub tags: Vec<String>,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// All possible enum values, with their optional Tile infos.
+	#[serde(rename = "values")]
+	pub values: Vec<EnumValueDefinition>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EnumValueDefinition {
+	/// An array of 4 Int values that refers to the tile in the tileset image: `[ x, y, width,
+	/// height ]`
+	#[serde(rename = "__tileSrcRect")]
+	pub tile_src_rect: Option<Vec<i64>>,
+
+	/// Optional color
+	#[serde(rename = "color")]
+	pub color: i64,
+
+	/// Enum value
+	#[serde(rename = "id")]
+	pub id: String,
+
+	/// The optional ID of the tile
+	#[serde(rename = "tileId")]
+	pub tile_id: Option<i64>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LayerDefinition {
+	/// Type of the layer (*IntGrid, Entities, Tiles or AutoLayer*)
+	#[serde(rename = "__type")]
+	pub layer_definition_type: String,
+
+	/// Contains all the auto-layer rule definitions.
+	#[serde(rename = "autoRuleGroups")]
+	pub auto_rule_groups: Vec<AutoLayerRuleGroup>,
+
+	#[serde(rename = "autoSourceLayerDefUid")]
+	pub auto_source_layer_def_uid: Option<i64>,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 1.2.0  Replaced
+	/// by: `tilesetDefUid`
+	#[serde(rename = "autoTilesetDefUid")]
+	pub auto_tileset_def_uid: Option<i64>,
+
+	/// Allow editor selections when the layer is not currently active.
+	#[serde(rename = "canSelectWhenInactive")]
+	pub can_select_when_inactive: bool,
+
+	/// Opacity of the layer (0 to 1.0)
+	#[serde(rename = "displayOpacity")]
+	pub display_opacity: f64,
+
+	/// User defined documentation for this element to provide help/tips to level designers.
+	#[serde(rename = "doc")]
+	pub doc: Option<String>,
+
+	/// An array of tags to forbid some Entities in this layer
+	#[serde(rename = "excludedTags")]
+	pub excluded_tags: Vec<String>,
+
+	/// Width and height of the grid in pixels
+	#[serde(rename = "gridSize")]
+	pub grid_size: i64,
+
+	/// Height of the optional "guide" grid in pixels
+	#[serde(rename = "guideGridHei")]
+	pub guide_grid_hei: i64,
+
+	/// Width of the optional "guide" grid in pixels
+	#[serde(rename = "guideGridWid")]
+	pub guide_grid_wid: i64,
+
+	#[serde(rename = "hideFieldsWhenInactive")]
+	pub hide_fields_when_inactive: bool,
+
+	/// Hide the layer from the list on the side of the editor view.
+	#[serde(rename = "hideInList")]
+	pub hide_in_list: bool,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Alpha of this layer when it is not the active one.
+	#[serde(rename = "inactiveOpacity")]
+	pub inactive_opacity: f64,
+
+	/// An array that defines extra optional info for each IntGrid value.<br/>  WARNING: the
+	/// array order is not related to actual IntGrid values! As user can re-order IntGrid values
+	/// freely, you may value "2" before value "1" in this array.
+	#[serde(rename = "intGridValues")]
+	pub int_grid_values: Vec<IntGridValueDefinition>,
+
+	/// Parallax horizontal factor (from -1 to 1, defaults to 0) which affects the scrolling
+	/// speed of this layer, creating a fake 3D (parallax) effect.
+	#[serde(rename = "parallaxFactorX")]
+	pub parallax_factor_x: f64,
+
+	/// Parallax vertical factor (from -1 to 1, defaults to 0) which affects the scrolling speed
+	/// of this layer, creating a fake 3D (parallax) effect.
+	#[serde(rename = "parallaxFactorY")]
+	pub parallax_factor_y: f64,
+
+	/// If true (default), a layer with a parallax factor will also be scaled up/down accordingly.
+	#[serde(rename = "parallaxScaling")]
+	pub parallax_scaling: bool,
+
+	/// X offset of the layer, in pixels (IMPORTANT: this should be added to the `LayerInstance`
+	/// optional offset)
+	#[serde(rename = "pxOffsetX")]
+	pub px_offset_x: i64,
+
+	/// Y offset of the layer, in pixels (IMPORTANT: this should be added to the `LayerInstance`
+	/// optional offset)
+	#[serde(rename = "pxOffsetY")]
+	pub px_offset_y: i64,
+
+	/// An array of tags to filter Entities that can be added to this layer
+	#[serde(rename = "requiredTags")]
+	pub required_tags: Vec<String>,
+
+	/// If the tiles are smaller or larger than the layer grid, the pivot value will be used to
+	/// position the tile relatively its grid cell.
+	#[serde(rename = "tilePivotX")]
+	pub tile_pivot_x: f64,
+
+	/// If the tiles are smaller or larger than the layer grid, the pivot value will be used to
+	/// position the tile relatively its grid cell.
+	#[serde(rename = "tilePivotY")]
+	pub tile_pivot_y: f64,
+
+	/// Reference to the default Tileset UID being used by this layer definition.<br/>
+	/// **WARNING**: some layer *instances* might use a different tileset. So most of the time,
+	/// you should probably use the `__tilesetDefUid` value found in layer instances.<br/>  Note:
+	/// since version 1.0.0, the old `autoTilesetDefUid` was removed and merged into this value.
+	#[serde(rename = "tilesetDefUid")]
+	pub tileset_def_uid: Option<i64>,
+
+	/// Type of the layer as Haxe Enum Possible values: `IntGrid`, `Entities`, `Tiles`,
+	/// `AutoLayer`
+	#[serde(rename = "type")]
+	pub purple_type: Type,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AutoLayerRuleGroup {
+	#[serde(rename = "active")]
+	pub active: bool,
+
+	/// *This field was removed in 1.0.0 and should no longer be used.*
+	#[serde(rename = "collapsed")]
+	pub collapsed: Option<bool>,
+
+	#[serde(rename = "isOptional")]
+	pub is_optional: bool,
+
+	#[serde(rename = "name")]
+	pub name: String,
+
+	#[serde(rename = "rules")]
+	pub rules: Vec<AutoLayerRuleDefinition>,
+
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	#[serde(rename = "usesWizard")]
+	pub uses_wizard: bool,
+}
+
+/// This complex section isn't meant to be used by game devs at all, as these rules are
+/// completely resolved internally by the editor before any saving. You should just ignore
+/// this part.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct AutoLayerRuleDefinition {
+	/// If FALSE, the rule effect isn't applied, and no tiles are generated.
+	#[serde(rename = "active")]
+	pub active: bool,
+
+	/// When TRUE, the rule will prevent other rules to be applied in the same cell if it matches
+	/// (TRUE by default).
+	#[serde(rename = "breakOnMatch")]
+	pub break_on_match: bool,
+
+	/// Chances for this rule to be applied (0 to 1)
+	#[serde(rename = "chance")]
+	pub chance: f64,
+
+	/// Checker mode Possible values: `None`, `Horizontal`, `Vertical`
+	#[serde(rename = "checker")]
+	pub checker: Checker,
+
+	/// If TRUE, allow rule to be matched by flipping its pattern horizontally
+	#[serde(rename = "flipX")]
+	pub flip_x: bool,
+
+	/// If TRUE, allow rule to be matched by flipping its pattern vertically
+	#[serde(rename = "flipY")]
+	pub flip_y: bool,
+
+	/// Default IntGrid value when checking cells outside of level bounds
+	#[serde(rename = "outOfBoundsValue")]
+	pub out_of_bounds_value: Option<i64>,
+
+	/// Rule pattern (size x size)
+	#[serde(rename = "pattern")]
+	pub pattern: Vec<i64>,
+
+	/// If TRUE, enable Perlin filtering to only apply rule on specific random area
+	#[serde(rename = "perlinActive")]
+	pub perlin_active: bool,
+
+	#[serde(rename = "perlinOctaves")]
+	pub perlin_octaves: f64,
+
+	#[serde(rename = "perlinScale")]
+	pub perlin_scale: f64,
+
+	#[serde(rename = "perlinSeed")]
+	pub perlin_seed: f64,
+
+	/// X pivot of a tile stamp (0-1)
+	#[serde(rename = "pivotX")]
+	pub pivot_x: f64,
+
+	/// Y pivot of a tile stamp (0-1)
+	#[serde(rename = "pivotY")]
+	pub pivot_y: f64,
+
+	/// Pattern width & height. Should only be 1,3,5 or 7.
+	#[serde(rename = "size")]
+	pub size: i64,
+
+	/// Array of all the tile IDs. They are used randomly or as stamps, based on `tileMode` value.
+	#[serde(rename = "tileIds")]
+	pub tile_ids: Vec<i64>,
+
+	/// Defines how tileIds array is used Possible values: `Single`, `Stamp`
+	#[serde(rename = "tileMode")]
+	pub tile_mode: TileMode,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// X cell coord modulo
+	#[serde(rename = "xModulo")]
+	pub x_modulo: i64,
+
+	/// X cell start offset
+	#[serde(rename = "xOffset")]
+	pub x_offset: i64,
+
+	/// Y cell coord modulo
+	#[serde(rename = "yModulo")]
+	pub y_modulo: i64,
+
+	/// Y cell start offset
+	#[serde(rename = "yOffset")]
+	pub y_offset: i64,
+}
+
+/// IntGrid value definition
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct IntGridValueDefinition {
+	#[serde(rename = "color")]
+	pub color: String,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: Option<String>,
+
+	/// The IntGrid value itself
+	#[serde(rename = "value")]
+	pub value: i64,
+}
+
+/// The `Tileset` definition is the most important part among project definitions. It
+/// contains some extra informations about each integrated tileset. If you only had to parse
+/// one definition section, that would be the one.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TilesetDefinition {
+	/// Grid-based height
+	#[serde(rename = "__cHei")]
+	pub c_hei: i64,
+
+	/// Grid-based width
+	#[serde(rename = "__cWid")]
+	pub c_wid: i64,
+
+	/// The following data is used internally for various optimizations. It's always synced with
+	/// source image changes.
+	#[serde(rename = "cachedPixelData")]
+	pub cached_pixel_data: Option<HashMap<String, Option<serde_json::Value>>>,
+
+	/// An array of custom tile metadata
+	#[serde(rename = "customData")]
+	pub custom_data: Vec<TileCustomMetadata>,
+
+	/// If this value is set, then it means that this atlas uses an internal LDtk atlas image
+	/// instead of a loaded one. Possible values: &lt;`null`&gt;, `LdtkIcons`
+	#[serde(rename = "embedAtlas")]
+	pub embed_atlas: Option<EmbedAtlas>,
+
+	/// Tileset tags using Enum values specified by `tagsSourceEnumId`. This array contains 1
+	/// element per Enum value, which contains an array of all Tile IDs that are tagged with it.
+	#[serde(rename = "enumTags")]
+	pub enum_tags: Vec<EnumTagValue>,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Distance in pixels from image borders
+	#[serde(rename = "padding")]
+	pub padding: i64,
+
+	/// Image height in pixels
+	#[serde(rename = "pxHei")]
+	pub px_hei: i64,
+
+	/// Image width in pixels
+	#[serde(rename = "pxWid")]
+	pub px_wid: i64,
+
+	/// Path to the source file, relative to the current project JSON file<br/>  It can be null
+	/// if no image was provided, or when using an embed atlas.
+	#[serde(rename = "relPath")]
+	pub rel_path: Option<String>,
+
+	/// Array of group of tiles selections, only meant to be used in the editor
+	#[serde(rename = "savedSelections")]
+	pub saved_selections: Vec<HashMap<String, Option<serde_json::Value>>>,
+
+	/// Space in pixels between all tiles
+	#[serde(rename = "spacing")]
+	pub spacing: i64,
+
+	/// An array of user-defined tags to organize the Tilesets
+	#[serde(rename = "tags")]
+	pub tags: Vec<String>,
+
+	/// Optional Enum definition UID used for this tileset meta-data
+	#[serde(rename = "tagsSourceEnumUid")]
+	pub tags_source_enum_uid: Option<i64>,
+
+	#[serde(rename = "tileGridSize")]
+	pub tile_grid_size: i64,
+
+	/// Unique Intidentifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+}
+
+/// In a tileset definition, user defined meta-data of a tile.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TileCustomMetadata {
+	#[serde(rename = "data")]
+	pub data: String,
+
+	#[serde(rename = "tileId")]
+	pub tile_id: i64,
+}
+
+/// In a tileset definition, enum based tag infos
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EnumTagValue {
+	#[serde(rename = "enumValueId")]
+	pub enum_value_id: String,
+
+	#[serde(rename = "tileIds")]
+	pub tile_ids: Vec<i64>,
+}
+
+/// This object is not actually used by LDtk. It ONLY exists to force explicit references to
+/// all types, to make sure QuickType finds them and integrate all of them. Otherwise,
+/// Quicktype will drop types that are not explicitely used.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ForcedRefs {
+	#[serde(rename = "AutoLayerRuleGroup")]
+	pub auto_layer_rule_group: Option<AutoLayerRuleGroup>,
+
+	#[serde(rename = "AutoRuleDef")]
+	pub auto_rule_def: Option<AutoLayerRuleDefinition>,
+
+	#[serde(rename = "CustomCommand")]
+	pub custom_command: Option<LdtkCustomCommand>,
+
+	#[serde(rename = "Definitions")]
+	pub definitions: Option<Definitions>,
+
+	#[serde(rename = "EntityDef")]
+	pub entity_def: Option<EntityDefinition>,
+
+	#[serde(rename = "EntityInstance")]
+	pub entity_instance: Option<EntityInstance>,
+
+	#[serde(rename = "EntityReferenceInfos")]
+	pub entity_reference_infos: Option<ReferenceToAnEntityInstance>,
+
+	#[serde(rename = "EnumDef")]
+	pub enum_def: Option<EnumDefinition>,
+
+	#[serde(rename = "EnumDefValues")]
+	pub enum_def_values: Option<EnumValueDefinition>,
+
+	#[serde(rename = "EnumTagValue")]
+	pub enum_tag_value: Option<EnumTagValue>,
+
+	#[serde(rename = "FieldDef")]
+	pub field_def: Option<FieldDefinition>,
+
+	#[serde(rename = "FieldInstance")]
+	pub field_instance: Option<FieldInstance>,
+
+	#[serde(rename = "GridPoint")]
+	pub grid_point: Option<GridPoint>,
+
+	#[serde(rename = "IntGridValueDef")]
+	pub int_grid_value_def: Option<IntGridValueDefinition>,
+
+	#[serde(rename = "IntGridValueInstance")]
+	pub int_grid_value_instance: Option<IntGridValueInstance>,
+
+	#[serde(rename = "LayerDef")]
+	pub layer_def: Option<LayerDefinition>,
+
+	#[serde(rename = "LayerInstance")]
+	pub layer_instance: Option<LayerInstance>,
+
+	#[serde(rename = "Level")]
+	pub level: Option<Level>,
+
+	#[serde(rename = "LevelBgPosInfos")]
+	pub level_bg_pos_infos: Option<LevelBackgroundPosition>,
+
+	#[serde(rename = "NeighbourLevel")]
+	pub neighbour_level: Option<NeighbourLevel>,
+
+	#[serde(rename = "TableOfContentEntry")]
+	pub table_of_content_entry: Option<LdtkTableOfContentEntry>,
+
+	#[serde(rename = "Tile")]
+	pub tile: Option<TileInstance>,
+
+	#[serde(rename = "TileCustomMetadata")]
+	pub tile_custom_metadata: Option<TileCustomMetadata>,
+
+	#[serde(rename = "TilesetDef")]
+	pub tileset_def: Option<TilesetDefinition>,
+
+	#[serde(rename = "TilesetRect")]
+	pub tileset_rect: Option<TilesetRectangle>,
+
+	#[serde(rename = "World")]
+	pub world: Option<World>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct EntityInstance {
+	/// Grid-based coordinates (`[x,y]` format)
+	#[serde(rename = "__grid")]
+	pub grid: Vec<i64>,
+
+	/// Entity definition identifier
+	#[serde(rename = "__identifier")]
+	pub identifier: String,
+
+	/// Pivot coordinates  (`[x,y]` format, values are from 0 to 1) of the Entity
+	#[serde(rename = "__pivot")]
+	pub pivot: Vec<f64>,
+
+	/// The entity "smart" color, guessed from either Entity definition, or one its field
+	/// instances.
+	#[serde(rename = "__smartColor")]
+	pub smart_color: String,
+
+	/// Array of tags defined in this Entity definition
+	#[serde(rename = "__tags")]
+	pub tags: Vec<String>,
+
+	/// Optional TilesetRect used to display this entity (it could either be the default Entity
+	/// tile, or some tile provided by a field value, like an Enum).
+	#[serde(rename = "__tile")]
+	pub tile: Option<TilesetRectangle>,
+
+	/// Reference of the **Entity definition** UID
+	#[serde(rename = "defUid")]
+	pub def_uid: i64,
+
+	/// An array of all custom fields and their values.
+	#[serde(rename = "fieldInstances")]
+	pub field_instances: Vec<FieldInstance>,
+
+	/// Entity height in pixels. For non-resizable entities, it will be the same as Entity
+	/// definition.
+	#[serde(rename = "height")]
+	pub height: i64,
+
+	/// Unique instance identifier
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// Pixel coordinates (`[x,y]` format) in current level coordinate space. Don't forget
+	/// optional layer offsets, if they exist!
+	#[serde(rename = "px")]
+	pub px: Vec<i64>,
+
+	/// Entity width in pixels. For non-resizable entities, it will be the same as Entity
+	/// definition.
+	#[serde(rename = "width")]
+	pub width: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct FieldInstance {
+	/// Field definition identifier
+	#[serde(rename = "__identifier")]
+	pub identifier: String,
+
+	/// Optional TilesetRect used to display this field (this can be the field own Tile, or some
+	/// other Tile guessed from the value, like an Enum).
+	#[serde(rename = "__tile")]
+	pub tile: Option<TilesetRectangle>,
+
+	/// Type of the field, such as `Int`, `Float`, `String`, `Enum(my_enum_name)`, `Bool`,
+	/// etc.<br/>  NOTE: if you enable the advanced option **Use Multilines type**, you will have
+	/// "*Multilines*" instead of "*String*" when relevant.
+	#[serde(rename = "__type")]
+	pub field_instance_type: String,
+
+	/// Actual value of the field instance. The value type varies, depending on `__type`:<br/>
+	/// - For **classic types** (ie. Integer, Float, Boolean, String, Text and FilePath), you
+	/// just get the actual value with the expected type.<br/>   - For **Color**, the value is an
+	/// hexadecimal string using "#rrggbb" format.<br/>   - For **Enum**, the value is a String
+	/// representing the selected enum value.<br/>   - For **Point**, the value is a
+	/// [GridPoint](#ldtk-GridPoint) object.<br/>   - For **Tile**, the value is a
+	/// [TilesetRect](#ldtk-TilesetRect) object.<br/>   - For **EntityRef**, the value is an
+	/// [EntityReferenceInfos](#ldtk-EntityReferenceInfos) object.<br/><br/>  If the field is an
+	/// array, then this `__value` will also be a JSON array.
+	#[serde(rename = "__value")]
+	pub value: Option<serde_json::Value>,
+
+	/// Reference of the **Field definition** UID
+	#[serde(rename = "defUid")]
+	pub def_uid: i64,
+
+	/// Editor internal raw values
+	#[serde(rename = "realEditorValues")]
+	pub real_editor_values: Vec<Option<serde_json::Value>>,
+}
+
+/// This object describes the "location" of an Entity instance in the project worlds.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ReferenceToAnEntityInstance {
+	/// IID of the refered EntityInstance
+	#[serde(rename = "entityIid")]
+	pub entity_iid: String,
+
+	/// IID of the LayerInstance containing the refered EntityInstance
+	#[serde(rename = "layerIid")]
+	pub layer_iid: String,
+
+	/// IID of the Level containing the refered EntityInstance
+	#[serde(rename = "levelIid")]
+	pub level_iid: String,
+
+	/// IID of the World containing the refered EntityInstance
+	#[serde(rename = "worldIid")]
+	pub world_iid: String,
+}
+
+/// This object is just a grid-based coordinate used in Field values.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct GridPoint {
+	/// X grid-based coordinate
+	#[serde(rename = "cx")]
+	pub cx: i64,
+
+	/// Y grid-based coordinate
+	#[serde(rename = "cy")]
+	pub cy: i64,
+}
+
+/// IntGrid value instance
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct IntGridValueInstance {
+	/// Coordinate ID in the layer grid
+	#[serde(rename = "coordId")]
+	pub coord_id: i64,
+
+	/// IntGrid value
+	#[serde(rename = "v")]
+	pub v: i64,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LayerInstance {
+	/// Grid-based height
+	#[serde(rename = "__cHei")]
+	pub c_hei: i64,
+
+	/// Grid-based width
+	#[serde(rename = "__cWid")]
+	pub c_wid: i64,
+
+	/// Grid size
+	#[serde(rename = "__gridSize")]
+	pub grid_size: i64,
+
+	/// Layer definition identifier
+	#[serde(rename = "__identifier")]
+	pub identifier: String,
+
+	/// Layer opacity as Float [0-1]
+	#[serde(rename = "__opacity")]
+	pub opacity: f64,
+
+	/// Total layer X pixel offset, including both instance and definition offsets.
+	#[serde(rename = "__pxTotalOffsetX")]
+	pub px_total_offset_x: i64,
+
+	/// Total layer Y pixel offset, including both instance and definition offsets.
+	#[serde(rename = "__pxTotalOffsetY")]
+	pub px_total_offset_y: i64,
+
+	/// The definition UID of corresponding Tileset, if any.
+	#[serde(rename = "__tilesetDefUid")]
+	pub tileset_def_uid: Option<i64>,
+
+	/// The relative path to corresponding Tileset, if any.
+	#[serde(rename = "__tilesetRelPath")]
+	pub tileset_rel_path: Option<String>,
+
+	/// Layer type (possible values: IntGrid, Entities, Tiles or AutoLayer)
+	#[serde(rename = "__type")]
+	pub layer_instance_type: String,
+
+	/// An array containing all tiles generated by Auto-layer rules. The array is already sorted
+	/// in display order (ie. 1st tile is beneath 2nd, which is beneath 3rd etc.).<br/><br/>
+	/// Note: if multiple tiles are stacked in the same cell as the result of different rules,
+	/// all tiles behind opaque ones will be discarded.
+	#[serde(rename = "autoLayerTiles")]
+	pub auto_layer_tiles: Vec<TileInstance>,
+
+	#[serde(rename = "entityInstances")]
+	pub entity_instances: Vec<EntityInstance>,
+
+	#[serde(rename = "gridTiles")]
+	pub grid_tiles: Vec<TileInstance>,
+
+	/// Unique layer instance identifier
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 1.0.0  Replaced
+	/// by: `intGridCsv`
+	#[serde(rename = "intGrid")]
+	pub int_grid: Option<Vec<IntGridValueInstance>>,
+
+	/// A list of all values in the IntGrid layer, stored in CSV format (Comma Separated
+	/// Values).<br/>  Order is from left to right, and top to bottom (ie. first row from left to
+	/// right, followed by second row, etc).<br/>  `0` means "empty cell" and IntGrid values
+	/// start at 1.<br/>  The array size is `__cWid` x `__cHei` cells.
+	#[serde(rename = "intGridCsv")]
+	pub int_grid_csv: Vec<i64>,
+
+	/// Reference the Layer definition UID
+	#[serde(rename = "layerDefUid")]
+	pub layer_def_uid: i64,
+
+	/// Reference to the UID of the level containing this layer instance
+	#[serde(rename = "levelId")]
+	pub level_id: i64,
+
+	/// An Array containing the UIDs of optional rules that were enabled in this specific layer
+	/// instance.
+	#[serde(rename = "optionalRules")]
+	pub optional_rules: Vec<i64>,
+
+	/// This layer can use another tileset by overriding the tileset UID here.
+	#[serde(rename = "overrideTilesetUid")]
+	pub override_tileset_uid: Option<i64>,
+
+	/// X offset in pixels to render this layer, usually 0 (IMPORTANT: this should be added to
+	/// the `LayerDef` optional offset, so you should probably prefer using `__pxTotalOffsetX`
+	/// which contains the total offset value)
+	#[serde(rename = "pxOffsetX")]
+	pub px_offset_x: i64,
+
+	/// Y offset in pixels to render this layer, usually 0 (IMPORTANT: this should be added to
+	/// the `LayerDef` optional offset, so you should probably prefer using `__pxTotalOffsetX`
+	/// which contains the total offset value)
+	#[serde(rename = "pxOffsetY")]
+	pub px_offset_y: i64,
+
+	/// Random seed used for Auto-Layers rendering
+	#[serde(rename = "seed")]
+	pub seed: i64,
+
+	/// Layer instance visibility
+	#[serde(rename = "visible")]
+	pub visible: bool,
+}
+
+/// This structure represents a single tile from a given Tileset.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct TileInstance {
+	/// Internal data used by the editor.<br/>  For auto-layer tiles: `[ruleId, coordId]`.<br/>
+	/// For tile-layer tiles: `[coordId]`.
+	#[serde(rename = "d")]
+	pub d: Vec<i64>,
+
+	/// "Flip bits", a 2-bits integer to represent the mirror transformations of the tile.<br/>
+	/// - Bit 0 = X flip<br/>   - Bit 1 = Y flip<br/>   Examples: f=0 (no flip), f=1 (X flip
+	/// only), f=2 (Y flip only), f=3 (both flips)
+	#[serde(rename = "f")]
+	pub f: i64,
+
+	/// Pixel coordinates of the tile in the **layer** (`[x,y]` format). Don't forget optional
+	/// layer offsets, if they exist!
+	#[serde(rename = "px")]
+	pub px: Vec<i64>,
+
+	/// Pixel coordinates of the tile in the **tileset** (`[x,y]` format)
+	#[serde(rename = "src")]
+	pub src: Vec<i64>,
+
+	/// The *Tile ID* in the corresponding tileset.
+	#[serde(rename = "t")]
+	pub t: i64,
+}
+
+/// This section contains all the level data. It can be found in 2 distinct forms, depending
+/// on Project current settings:  - If "*Separate level files*" is **disabled** (default):
+/// full level data is *embedded* inside the main Project JSON file, - If "*Separate level
+/// files*" is **enabled**: level data is stored in *separate* standalone `.ldtkl` files (one
+/// per level). In this case, the main Project JSON file will still contain most level data,
+/// except heavy sections, like the `layerInstances` array (which will be null). The
+/// `externalRelPath` string points to the `ldtkl` file.  A `ldtkl` file is just a JSON file
+/// containing exactly what is described below.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct Level {
+	/// Background color of the level (same as `bgColor`, except the default value is
+	/// automatically used here if its value is `null`)
+	#[serde(rename = "__bgColor")]
+	pub bg_color: String,
+
+	/// Position informations of the background image, if there is one.
+	#[serde(rename = "__bgPos")]
+	pub bg_pos: Option<LevelBackgroundPosition>,
+
+	/// An array listing all other levels touching this one on the world map.<br/>  Only relevant
+	/// for world layouts where level spatial positioning is manual (ie. GridVania, Free). For
+	/// Horizontal and Vertical layouts, this array is always empty.
+	#[serde(rename = "__neighbours")]
+	pub neighbours: Vec<NeighbourLevel>,
+
+	/// The "guessed" color for this level in the editor, decided using either the background
+	/// color or an existing custom field.
+	#[serde(rename = "__smartColor")]
+	pub smart_color: String,
+
+	/// Background color of the level. If `null`, the project `defaultLevelBgColor` should be
+	/// used.
+	#[serde(rename = "bgColor")]
+	pub level_bg_color: Option<String>,
+
+	/// Background image X pivot (0-1)
+	#[serde(rename = "bgPivotX")]
+	pub bg_pivot_x: f64,
+
+	/// Background image Y pivot (0-1)
+	#[serde(rename = "bgPivotY")]
+	pub bg_pivot_y: f64,
+
+	/// An enum defining the way the background image (if any) is positioned on the level. See
+	/// `__bgPos` for resulting position info. Possible values: &lt;`null`&gt;, `Unscaled`,
+	/// `Contain`, `Cover`, `CoverDirty`
+	#[serde(rename = "bgPos")]
+	pub level_bg_pos: Option<BgPos>,
+
+	/// The *optional* relative path to the level background image.
+	#[serde(rename = "bgRelPath")]
+	pub bg_rel_path: Option<String>,
+
+	/// This value is not null if the project option "*Save levels separately*" is enabled. In
+	/// this case, this **relative** path points to the level Json file.
+	#[serde(rename = "externalRelPath")]
+	pub external_rel_path: Option<String>,
+
+	/// An array containing this level custom field values.
+	#[serde(rename = "fieldInstances")]
+	pub field_instances: Vec<FieldInstance>,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Unique instance identifier
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// An array containing all Layer instances. **IMPORTANT**: if the project option "*Save
+	/// levels separately*" is enabled, this field will be `null`.<br/>  This array is **sorted
+	/// in display order**: the 1st layer is the top-most and the last is behind.
+	#[serde(rename = "layerInstances")]
+	pub layer_instances: Option<Vec<LayerInstance>>,
+
+	/// Height of the level in pixels
+	#[serde(rename = "pxHei")]
+	pub px_hei: i64,
+
+	/// Width of the level in pixels
+	#[serde(rename = "pxWid")]
+	pub px_wid: i64,
+
+	/// Unique Int identifier
+	#[serde(rename = "uid")]
+	pub uid: i64,
+
+	/// If TRUE, the level identifier will always automatically use the naming pattern as defined
+	/// in `Project.levelNamePattern`. Becomes FALSE if the identifier is manually modified by
+	/// user.
+	#[serde(rename = "useAutoIdentifier")]
+	pub use_auto_identifier: bool,
+
+	/// Index that represents the "depth" of the level in the world. Default is 0, greater means
+	/// "above", lower means "below".<br/>  This value is mostly used for display only and is
+	/// intended to make stacking of levels easier to manage.
+	#[serde(rename = "worldDepth")]
+	pub world_depth: i64,
+
+	/// World X coordinate in pixels.<br/>  Only relevant for world layouts where level spatial
+	/// positioning is manual (ie. GridVania, Free). For Horizontal and Vertical layouts, the
+	/// value is always -1 here.
+	#[serde(rename = "worldX")]
+	pub world_x: i64,
+
+	/// World Y coordinate in pixels.<br/>  Only relevant for world layouts where level spatial
+	/// positioning is manual (ie. GridVania, Free). For Horizontal and Vertical layouts, the
+	/// value is always -1 here.
+	#[serde(rename = "worldY")]
+	pub world_y: i64,
+}
+
+/// Level background image position info
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LevelBackgroundPosition {
+	/// An array of 4 float values describing the cropped sub-rectangle of the displayed
+	/// background image. This cropping happens when original is larger than the level bounds.
+	/// Array format: `[ cropX, cropY, cropWidth, cropHeight ]`
+	#[serde(rename = "cropRect")]
+	pub crop_rect: Vec<f64>,
+
+	/// An array containing the `[scaleX,scaleY]` values of the **cropped** background image,
+	/// depending on `bgPos` option.
+	#[serde(rename = "scale")]
+	pub scale: Vec<f64>,
+
+	/// An array containing the `[x,y]` pixel coordinates of the top-left corner of the
+	/// **cropped** background image, depending on `bgPos` option.
+	#[serde(rename = "topLeftPx")]
+	pub top_left_px: Vec<i64>,
+}
+
+/// Nearby level info
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct NeighbourLevel {
+	/// A single lowercase character tipping on the level location (`n`orth, `s`outh, `w`est,
+	/// `e`ast).
+	#[serde(rename = "dir")]
+	pub dir: String,
+
+	/// Neighbour Instance Identifier
+	#[serde(rename = "levelIid")]
+	pub level_iid: String,
+
+	/// **WARNING**: this deprecated value is no longer exported since version 1.2.0  Replaced
+	/// by: `levelIid`
+	#[serde(rename = "levelUid")]
+	pub level_uid: Option<i64>,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct LdtkTableOfContentEntry {
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	#[serde(rename = "instances")]
+	pub instances: Vec<ReferenceToAnEntityInstance>,
+}
+
+/// **IMPORTANT**: this type is not used *yet* in current LDtk version. It's only presented
+/// here as a preview of a planned feature.  A World contains multiple levels, and it has its
+/// own layout settings.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct World {
+	/// Default new level height
+	#[serde(rename = "defaultLevelHeight")]
+	pub default_level_height: i64,
+
+	/// Default new level width
+	#[serde(rename = "defaultLevelWidth")]
+	pub default_level_width: i64,
+
+	/// User defined unique identifier
+	#[serde(rename = "identifier")]
+	pub identifier: String,
+
+	/// Unique instance identifer
+	#[serde(rename = "iid")]
+	pub iid: String,
+
+	/// All levels from this world. The order of this array is only relevant in
+	/// `LinearHorizontal` and `linearVertical` world layouts (see `worldLayout` value).
+	/// Otherwise, you should refer to the `worldX`,`worldY` coordinates of each Level.
+	#[serde(rename = "levels")]
+	pub levels: Vec<Level>,
+
+	/// Height of the world grid in pixels.
+	#[serde(rename = "worldGridHeight")]
+	pub world_grid_height: i64,
+
+	/// Width of the world grid in pixels.
+	#[serde(rename = "worldGridWidth")]
+	pub world_grid_width: i64,
+
+	/// An enum that describes how levels are organized in this project (ie. linearly or in a 2D
+	/// space). Possible values: `Free`, `GridVania`, `LinearHorizontal`, `LinearVertical`, `null`
+	#[serde(rename = "worldLayout")]
+	pub world_layout: Option<WorldLayout>,
+}
+
+/// Possible values: `Manual`, `AfterLoad`, `BeforeSave`, `AfterSave`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum When {
+	#[serde(rename = "AfterLoad")]
+	AfterLoad,
+
+	#[serde(rename = "AfterSave")]
+	AfterSave,
+
+	#[serde(rename = "BeforeSave")]
+	BeforeSave,
+
+	#[serde(rename = "Manual")]
+	Manual,
+}
+
+/// Possible values: `Any`, `OnlySame`, `OnlyTags`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum AllowedRefs {
+	#[serde(rename = "Any")]
+	Any,
+
+	#[serde(rename = "OnlySame")]
+	OnlySame,
+
+	#[serde(rename = "OnlyTags")]
+	OnlyTags,
+}
+
+/// Possible values: `Hidden`, `ValueOnly`, `NameAndValue`, `EntityTile`, `Points`,
+/// `PointStar`, `PointPath`, `PointPathLoop`, `RadiusPx`, `RadiusGrid`,
+/// `ArrayCountWithLabel`, `ArrayCountNoLabel`, `RefLinkBetweenPivots`,
+/// `RefLinkBetweenCenters`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum EditorDisplayMode {
+	#[serde(rename = "ArrayCountNoLabel")]
+	ArrayCountNoLabel,
+
+	#[serde(rename = "ArrayCountWithLabel")]
+	ArrayCountWithLabel,
+
+	#[serde(rename = "EntityTile")]
+	EntityTile,
+
+	#[serde(rename = "Hidden")]
+	Hidden,
+
+	#[serde(rename = "NameAndValue")]
+	NameAndValue,
+
+	#[serde(rename = "PointPath")]
+	PointPath,
+
+	#[serde(rename = "PointPathLoop")]
+	PointPathLoop,
+
+	#[serde(rename = "PointStar")]
+	PointStar,
+
+	#[serde(rename = "Points")]
+	Points,
+
+	#[serde(rename = "RadiusGrid")]
+	RadiusGrid,
+
+	#[serde(rename = "RadiusPx")]
+	RadiusPx,
+
+	#[serde(rename = "RefLinkBetweenCenters")]
+	RefLinkBetweenCenters,
+
+	#[serde(rename = "RefLinkBetweenPivots")]
+	RefLinkBetweenPivots,
+
+	#[serde(rename = "ValueOnly")]
+	ValueOnly,
+}
+
+/// Possible values: `Above`, `Center`, `Beneath`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum EditorDisplayPos {
+	#[serde(rename = "Above")]
+	Above,
+
+	#[serde(rename = "Beneath")]
+	Beneath,
+
+	#[serde(rename = "Center")]
+	Center,
+}
+
+/// Possible values: `ZigZag`, `StraightArrow`, `CurvedArrow`, `ArrowsLine`, `DashedLine`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum EditorLinkStyle {
+	#[serde(rename = "ArrowsLine")]
+	ArrowsLine,
+
+	#[serde(rename = "CurvedArrow")]
+	CurvedArrow,
+
+	#[serde(rename = "DashedLine")]
+	DashedLine,
+
+	#[serde(rename = "StraightArrow")]
+	StraightArrow,
+
+	#[serde(rename = "ZigZag")]
+	ZigZag,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum TextLanguageMode {
+	#[serde(rename = "LangC")]
+	LangC,
+
+	#[serde(rename = "LangHaxe")]
+	LangHaxe,
+
+	#[serde(rename = "LangJS")]
+	LangJs,
+
+	#[serde(rename = "LangJson")]
+	LangJson,
+
+	#[serde(rename = "LangLog")]
+	LangLog,
+
+	#[serde(rename = "LangLua")]
+	LangLua,
+
+	#[serde(rename = "LangMarkdown")]
+	LangMarkdown,
+
+	#[serde(rename = "LangPython")]
+	LangPython,
+
+	#[serde(rename = "LangRuby")]
+	LangRuby,
+
+	#[serde(rename = "LangXml")]
+	LangXml,
+}
+
+/// Possible values: `DiscardOldOnes`, `PreventAdding`, `MoveLastOne`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum LimitBehavior {
+	#[serde(rename = "DiscardOldOnes")]
+	DiscardOldOnes,
+
+	#[serde(rename = "MoveLastOne")]
+	MoveLastOne,
+
+	#[serde(rename = "PreventAdding")]
+	PreventAdding,
+}
+
+/// If TRUE, the maxCount is a "per world" limit, if FALSE, it's a "per level". Possible
+/// values: `PerLayer`, `PerLevel`, `PerWorld`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum LimitScope {
+	#[serde(rename = "PerLayer")]
+	PerLayer,
+
+	#[serde(rename = "PerLevel")]
+	PerLevel,
+
+	#[serde(rename = "PerWorld")]
+	PerWorld,
+}
+
+/// Possible values: `Rectangle`, `Ellipse`, `Tile`, `Cross`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum RenderMode {
+	#[serde(rename = "Cross")]
+	Cross,
+
+	#[serde(rename = "Ellipse")]
+	Ellipse,
+
+	#[serde(rename = "Rectangle")]
+	Rectangle,
+
+	#[serde(rename = "Tile")]
+	Tile,
+}
+
+/// An enum describing how the the Entity tile is rendered inside the Entity bounds. Possible
+/// values: `Cover`, `FitInside`, `Repeat`, `Stretch`, `FullSizeCropped`,
+/// `FullSizeUncropped`, `NineSlice`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum TileRenderMode {
+	#[serde(rename = "Cover")]
+	Cover,
+
+	#[serde(rename = "FitInside")]
+	FitInside,
+
+	#[serde(rename = "FullSizeCropped")]
+	FullSizeCropped,
+
+	#[serde(rename = "FullSizeUncropped")]
+	FullSizeUncropped,
+
+	#[serde(rename = "NineSlice")]
+	NineSlice,
+
+	#[serde(rename = "Repeat")]
+	Repeat,
+
+	#[serde(rename = "Stretch")]
+	Stretch,
+}
+
+/// Checker mode Possible values: `None`, `Horizontal`, `Vertical`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Checker {
+	#[serde(rename = "Horizontal")]
+	Horizontal,
+
+	#[serde(rename = "None")]
+	None,
+
+	#[serde(rename = "Vertical")]
+	Vertical,
+}
+
+/// Defines how tileIds array is used Possible values: `Single`, `Stamp`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum TileMode {
+	#[serde(rename = "Single")]
+	Single,
+
+	#[serde(rename = "Stamp")]
+	Stamp,
+}
+
+/// Type of the layer as Haxe Enum Possible values: `IntGrid`, `Entities`, `Tiles`,
+/// `AutoLayer`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Type {
+	#[serde(rename = "AutoLayer")]
+	AutoLayer,
+
+	#[serde(rename = "Entities")]
+	Entities,
+
+	#[serde(rename = "IntGrid")]
+	IntGrid,
+
+	#[serde(rename = "Tiles")]
+	Tiles,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum EmbedAtlas {
+	#[serde(rename = "LdtkIcons")]
+	LdtkIcons,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum Flag {
+	#[serde(rename = "DiscardPreCsvIntGrid")]
+	DiscardPreCsvIntGrid,
+
+	#[serde(rename = "ExportPreCsvIntGridFormat")]
+	ExportPreCsvIntGridFormat,
+
+	#[serde(rename = "IgnoreBackupSuggest")]
+	IgnoreBackupSuggest,
+
+	#[serde(rename = "MultiWorlds")]
+	MultiWorlds,
+
+	#[serde(rename = "PrependIndexToLevelFileNames")]
+	PrependIndexToLevelFileNames,
+
+	#[serde(rename = "UseMultilinesType")]
+	UseMultilinesType,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum BgPos {
+	#[serde(rename = "Contain")]
+	Contain,
+
+	#[serde(rename = "Cover")]
+	Cover,
+
+	#[serde(rename = "CoverDirty")]
+	CoverDirty,
+
+	#[serde(rename = "Unscaled")]
+	Unscaled,
+}
+
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum WorldLayout {
+	#[serde(rename = "Free")]
+	Free,
+
+	#[serde(rename = "GridVania")]
+	GridVania,
+
+	#[serde(rename = "LinearHorizontal")]
+	LinearHorizontal,
+
+	#[serde(rename = "LinearVertical")]
+	LinearVertical,
+}
+
+/// Naming convention for Identifiers (first-letter uppercase, full uppercase etc.) Possible
+/// values: `Capitalize`, `Uppercase`, `Lowercase`, `Free`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum IdentifierStyle {
+	#[serde(rename = "Capitalize")]
+	Capitalize,
+
+	#[serde(rename = "Free")]
+	Free,
+
+	#[serde(rename = "Lowercase")]
+	Lowercase,
+
+	#[serde(rename = "Uppercase")]
+	Uppercase,
+}
+
+/// "Image export" option when saving project. Possible values: `None`, `OneImagePerLayer`,
+/// `OneImagePerLevel`, `LayersAndLevels`
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum ImageExportMode {
+	#[serde(rename = "LayersAndLevels")]
+	LayersAndLevels,
+
+	#[serde(rename = "None")]
+	None,
+
+	#[serde(rename = "OneImagePerLayer")]
+	OneImagePerLayer,
+
+	#[serde(rename = "OneImagePerLevel")]
+	OneImagePerLevel,
+}
diff --git a/src/ldtk/mod.rs b/src/ldtk/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..d7c12de857ccf89ea7f4f1e81eb45349b1bda090
--- /dev/null
+++ b/src/ldtk/mod.rs
@@ -0,0 +1,77 @@
+#[cfg(feature = "ldtk_1_2_5")]
+mod data_1_2_5;
+
+#[cfg(feature = "ldtk_1_2_4")]
+mod data_1_2_4;
+
+use bevy::asset::{AssetLoader, BoxedFuture, LoadContext, LoadedAsset};
+use bevy::reflect::{TypeUuid, Uuid};
+#[cfg(feature = "ldtk_1_2_4")]
+pub use data_1_2_4::*;
+#[cfg(feature = "ldtk_1_2_5")]
+pub use data_1_2_5::*;
+
+#[derive(thiserror::Error)]
+pub enum ParseError {
+	#[error("Failed to parse file: {0}")]
+	SerdeError(#[from] String),
+}
+
+impl TypeUuid for Project {
+	const TYPE_UUID: Uuid = Uuid::from_u128(87988914102923589138720617793417023455);
+}
+
+impl Project {
+	pub fn from_bytes(bytes: &[u8]) -> Result<Self, ParseError> {
+		serde_json::from_slice(bytes).map_err(|e| ParseError::SerdeError(format!("{}", e)))
+	}
+}
+
+pub type LdtkProject = Project;
+
+impl<'a> TryFrom<&'a [u8]> for Project {
+	type Error = ParseError;
+
+	fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
+		Project::from_bytes(value)
+	}
+}
+
+impl<'a> From<&'a [u8]> for Project {
+	fn from(value: &'a [u8]) -> Self {
+		#[cfg(feature = "no_panic")]
+		{
+			match Project::from_bytes(value) {
+				Ok(val) => val,
+				Err(e) => {
+					log::error!("{}", e);
+					std::process::abort();
+				}
+			}
+		}
+
+		#[cfg(not(feature = "no_panic"))]
+		{
+			Project::from_bytes(value).expect("Failed to parse ldtk project file")
+		}
+	}
+}
+
+#[derive(Default)]
+pub struct LdtkLoader;
+impl AssetLoader for LdtkLoader {
+	fn load<'a>(
+		&'a self,
+		bytes: &'a [u8],
+		load_context: &'a mut LoadContext,
+	) -> BoxedFuture<'a, anyhow::Result<(), anyhow::Error>> {
+		Box::pin(async move {
+			load_context.set_default_asset(LoadedAsset::new(Project::from_bytes(bytes)?));
+			Ok(())
+		})
+	}
+
+	fn extensions(&self) -> &[&str] {
+		&["ldtk"]
+	}
+}
diff --git a/src/lib.rs b/src/lib.rs
index c280b1b71e5c8f4e1ac164f81a2f3b1a7caa9590..7bad7741847f4cacc49dc235c400bff152c0ca72 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,11 +1,11 @@
 mod assets;
 mod camera;
-mod locator;
 mod map_query;
 mod pregen;
-mod types;
-pub(crate) mod utils;
-// mod spawning;
+mod system;
+
+#[cfg(any(feature = "ldtk_1_2_5", feature = "ldtk_1_2_4"))]
+pub mod ldtk;
 
 pub static mut LDTK_TILE_SCALE: AtomicU32 = AtomicU32::new(32);
 pub fn get_ldtk_tile_scale() -> f32 {
@@ -29,17 +29,18 @@ mod __plugin {
 	use bevy::asset::AddAsset;
 	use bevy::ecs::query::ReadOnlyWorldQuery;
 
-	use crate::LevelDataUpdated;
-
 	pub struct MicroLDTKPlugin;
 	impl Plugin for MicroLDTKPlugin {
 		fn build(&self, app: &mut App) {
-			app.add_event::<LevelDataUpdated>()
-				.init_resource::<super::assets::TilesetIndex>()
-				.init_resource::<super::assets::LevelIndex>()
-				.add_asset::<super::assets::LdtkProject>()
-				.add_asset_loader(super::assets::LdtkLoader)
-				.add_system(super::assets::handle_ldtk_project_events);
+			#[cfg(any(feature = "ldtk_1_2_5", feature = "ldtk_1_2_4"))]
+			{
+				app.add_event::<super::types::LevelDataUpdated>()
+					.add_asset::<super::ldtk::Project>()
+					.add_asset_loader(super::ldtk::LdtkLoader)
+					.init_resource::<super::assets::TilesetIndex>()
+					.init_resource::<super::assets::LevelIndex>()
+					.add_system(super::assets::handle_ldtk_project_events);
+			}
 		}
 	}
 
@@ -79,8 +80,5 @@ pub use __plugin::{MicroLDTKCameraPlugin, MicroLDTKPlugin};
 pub use assets::{LdtkLoader, LdtkProject, LevelIndex, TileMetadata, TilesetIndex};
 pub use camera::CameraBounder;
 pub use map_query::{CameraBounds, MapQuery};
-pub use pregen::{
-	write_layer_to_texture, write_map_to_texture, Rasterise, SuppliesImage, SuppliesTextureAtlas,
-};
-pub use types::{LdtkLayer, LdtkLevel, LevelDataUpdated, SpatialIndex, TileFlip, TileRef};
-pub use utils::{entity_centre, grid_to_px, px_to_grid, ActiveLevel, Indexer, WorldLinked};
+pub use pregen::{write_layer_to_texture, write_map_to_texture, Rasterise};
+pub use system::*;
diff --git a/src/locator.rs b/src/locator.rs
deleted file mode 100644
index 34f1fac0a3991cb0354f540fce7cfb4914c24319..0000000000000000000000000000000000000000
--- a/src/locator.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-use bevy::prelude::{Handle, TextureAtlas};
-
-pub trait SuppliesTileAtlas {
-	fn from_path(path: impl ToString) -> Option<Handle<TextureAtlas>>;
-}
diff --git a/src/map_query.rs b/src/map_query.rs
index 43c62430623864616e01f0f583b63c70727d32c7..fe72d0c786b79adc381d5c5e9567cac76a23f0c4 100644
--- a/src/map_query.rs
+++ b/src/map_query.rs
@@ -4,9 +4,9 @@ use std::str::FromStr;
 
 use bevy::ecs::system::SystemParam;
 use bevy::prelude::*;
-use ldtk_rust::EntityInstance;
 
 use crate::assets::LevelIndex;
+use crate::ldtk::EntityInstance;
 use crate::utils::{ActiveLevel, SerdeClone};
 use crate::{get_ldtk_tile_scale, LdtkLayer, LdtkLevel};
 
diff --git a/src/pregen.rs b/src/pregen.rs
index 84cb9e467f672835f394014ae086631198e04356..b5c3bfd55f8d6bf4cf177c2362eb7d09fffdac85 100644
--- a/src/pregen.rs
+++ b/src/pregen.rs
@@ -2,7 +2,9 @@ use bevy::prelude::{Handle, Image, TextureAtlas};
 use bevy::render::render_resource::TextureFormat;
 use bevy::render::texture::TextureFormatPixelInfo;
 
-use crate::{get_ldtk_tile_scale, Indexer, LdtkLayer, LdtkLevel};
+use crate::{
+	get_ldtk_tile_scale, Indexer, LdtkLayer, LdtkLevel, SuppliesImage, SuppliesTextureAtlas,
+};
 
 pub fn write_layer_to_texture(
 	layer: &LdtkLayer,
@@ -70,15 +72,6 @@ pub fn write_map_to_texture(
 	}
 }
 
-pub trait SuppliesTextureAtlas {
-	fn get_atlas_handle(&self, name: impl ToString) -> Option<&Handle<TextureAtlas>>;
-	fn get_atlas(&self, name: &Handle<TextureAtlas>) -> Option<&TextureAtlas>;
-}
-pub trait SuppliesImage {
-	fn get_image_handle(&self, name: impl ToString) -> Option<&Handle<Image>>;
-	fn get_image(&self, handle: &Handle<Image>) -> Option<&Image>;
-}
-
 pub trait Rasterise {
 	fn write_to_texture(
 		&self,
diff --git a/src/spawning.rs b/src/spawning.rs
deleted file mode 100644
index 52fef25b82949518e694f17439679076f7748d1c..0000000000000000000000000000000000000000
--- a/src/spawning.rs
+++ /dev/null
@@ -1,107 +0,0 @@
-// use std::marker::PhantomData;
-//
-// use bevy::app::{App, Plugin};
-// use bevy::ecs::system::{SystemParam, SystemState};
-// use bevy::prelude::{
-// 	Commands, Component, DespawnRecursiveExt, Entity, In, Query, Res, ResMut, Resource, System,
-// 	With, World,
-// };
-// use ldtk_rust::{EntityInstance, Level};
-//
-// use crate::utils::SerdeClone;
-// use crate::{ActiveLevel, LevelIndex, MapQuery};
-//
-// #[derive(Component, Copy, Clone, Debug)]
-// pub struct LdtkDespawnTag;
-//
-// pub type TileSpawnerInput = (Level, LdtkDespawnTag);
-// pub type EntitySpawnerInput = Vec<EntityInstance>;
-//
-// fn noop_tile_system(_: In<TileSpawnerInput>) {}
-// fn noop_entity_system(_: In<EntitySpawnerInput>) {}
-//
-// #[derive(Resource)]
-// pub struct MapSpawner {
-// 	tile_spawner: Option<Box<dyn System<In = TileSpawnerInput, Out = ()>>>,
-// 	entity_spawner: Option<Box<dyn System<In = EntitySpawnerInput, Out = ()>>>,
-// }
-//
-// impl MapSpawner {
-// 	pub fn new(
-// 		tile_spawner: impl System<In = TileSpawnerInput, Out = ()>,
-// 		entity_spawner: impl System<In = EntitySpawnerInput, Out = ()>,
-// 	) -> Self {
-// 		MapSpawner {
-// 			tile_spawner: Some(Box::new(tile_spawner)),
-// 			entity_spawner: Some(Box::new(entity_spawner)),
-// 		}
-// 	}
-//
-// 	pub fn with_tile_spawner(tile_spawner: impl System<In = TileSpawnerInput, Out = ()>) -> Self {
-// 		MapSpawner {
-// 			tile_spawner: Some(Box::new(tile_spawner)),
-// 			entity_spawner: None,
-// 		}
-// 	}
-// 	pub fn with_entity_spawner(
-// 		entity_spawner: impl System<In = EntitySpawnerInput, Out = ()>,
-// 	) -> Self {
-// 		MapSpawner {
-// 			entity_spawner: Some(Box::new(entity_spawner)),
-// 			tile_spawner: None,
-// 		}
-// 	}
-//
-// 	pub fn run_tile_system(&mut self, level: &Level, world: &mut World) {
-// 		match self.tile_spawner {
-// 			Some(ref mut system) => {
-// 				system.run((level.serde_clone(), LdtkDespawnTag), world);
-// 			}
-// 			None => {}
-// 		}
-// 	}
-// 	pub fn run_entity_system(&mut self, level: &Level, world: &mut World) {
-// 		match self.entity_spawner {
-// 			Some(ref mut system) => {
-// 				let entity_list = MapQuery::get_owned_entities_of(level);
-// 				system.run(entity_list, world);
-// 			}
-// 			None => {}
-// 		}
-// 	}
-// }
-//
-// pub fn ldtk_spawning_system(
-// 	world: &mut World,
-// 	systems: &mut SystemState<(
-// 		Commands,
-// 		Option<Res<ActiveLevel>>,
-// 		Option<ResMut<MapSpawner>>,
-// 		Res<LevelIndex>,
-// 		Query<Entity, With<LdtkDespawnTag>>,
-// 	)>,
-// ) {
-// 	let (mut commands, active_level, mut spawning_systems, level_index, existing_query) =
-// 		systems.get_mut(world);
-//
-// 	let active_level = match active_level {
-// 		Some(res) => res,
-// 		None => return,
-// 	};
-//
-// 	if active_level.is_added() || (active_level.is_changed() && active_level.dirty) {
-// 		for entity in &existing_query {
-// 			commands.entity(entity).despawn_recursive();
-// 		}
-//
-// 		let level = match level_index.get(&active_level.map) {
-// 			Some(level) => level,
-// 			None => return,
-// 		};
-//
-// 		if let Some(mut spawning_systems) = spawning_systems {
-// 			spawning_systems.run_tile_system(level, world);
-// 			spawning_systems.run_entity_system(level, world);
-// 		}
-// 	}
-// }
diff --git a/src/system/locator.rs b/src/system/locator.rs
new file mode 100644
index 0000000000000000000000000000000000000000..c61db5cdd84029edc717c245423b50a97b3bb0b4
--- /dev/null
+++ b/src/system/locator.rs
@@ -0,0 +1,10 @@
+use bevy::prelude::{Handle, Image, TextureAtlas};
+
+pub trait SuppliesTextureAtlas {
+	fn get_atlas_handle(&self, name: impl ToString) -> Option<&Handle<TextureAtlas>>;
+	fn get_atlas(&self, name: &Handle<TextureAtlas>) -> Option<&TextureAtlas>;
+}
+pub trait SuppliesImage {
+	fn get_image_handle(&self, name: impl ToString) -> Option<&Handle<Image>>;
+	fn get_image(&self, handle: &Handle<Image>) -> Option<&Image>;
+}
diff --git a/src/system/mod.rs b/src/system/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..95310029952fb4e03cc2b600494e112625f95e57
--- /dev/null
+++ b/src/system/mod.rs
@@ -0,0 +1,7 @@
+mod locator;
+mod types;
+mod utils;
+
+pub use locator::*;
+pub use types::*;
+pub use utils::*;
diff --git a/src/types.rs b/src/system/types.rs
similarity index 99%
rename from src/types.rs
rename to src/system/types.rs
index c24dc7cbdb8a4045ae286b3f6b1baa5438869e61..2b0d7f014bd9899b6697e8d0cddc4280357da0b7 100644
--- a/src/types.rs
+++ b/src/system/types.rs
@@ -12,6 +12,7 @@ use quadtree_rs::Quadtree;
 use serde::{Deserialize, Serialize};
 use serde_json::{Map, Number, Value};
 
+use crate::ldtk::{EntityInstance, FieldInstance, LayerInstance, Level, TileInstance};
 use crate::utils::{Indexer, SerdeClone};
 use crate::{get_ldtk_tile_scale, px_to_grid, MapQuery};
 
diff --git a/src/utils.rs b/src/system/utils.rs
similarity index 81%
rename from src/utils.rs
rename to src/system/utils.rs
index d33f47f7fd2664c547b9673d6a41a3ba8140bbe9..0e58218ee804c2ac01f441e3c9cc9d02c87d0234 100644
--- a/src/utils.rs
+++ b/src/system/utils.rs
@@ -1,23 +1,8 @@
 use bevy::prelude::{Component, Resource};
-use ldtk_rust::EntityInstance;
 use num_traits::AsPrimitive;
-use serde::de::DeserializeOwned;
-use serde::Serialize;
 
 use crate::get_ldtk_tile_scale;
-
-pub trait SerdeClone {
-	fn serde_clone(&self) -> Self;
-}
-
-impl<T> SerdeClone for T
-where
-	T: Serialize + DeserializeOwned,
-{
-	fn serde_clone(&self) -> Self {
-		serde_json::from_value(serde_json::to_value(self).unwrap()).unwrap()
-	}
-}
+use crate::ldtk::EntityInstance;
 
 pub fn px_to_grid<T: AsPrimitive<i64>>(t: T) -> i64 {
 	t.as_() / (get_ldtk_tile_scale() as i64)