diff --git a/Cargo.toml b/Cargo.toml
index 98d2d55b503380eae2455ad6b7cc4aff8919e895..89f249c48598a703786ab9b6bac0c4b5addc89ba 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -7,6 +7,7 @@ authors = [
 	"Louis Capitanchik <louis@microhacks.co.uk>"
 ]
 repository = "https://lab.lcr.gr/microhacks/bevy-micro-ldtk.git"
+description = "Load data from LDTK, index it and make it accessible through Bevy assets, extract and use autotile rules"
 license = "Apache-2.0"
 
 [features]
diff --git a/README b/README
new file mode 100644
index 0000000000000000000000000000000000000000..8244098e7a1a8f3eb1fef6f02d8c7af6a360e7fd
--- /dev/null
+++ b/README
@@ -0,0 +1,86 @@
+# micro_ldtk
+
+`micro_ldtk` provides a feature rich layer on top of raw LDTK JSON data, focused on the Bevy engine, and with a goal
+of forward compatible support for as many LDTK schema versions as is sensible.
+
+## Installation
+
+By default, `micro_ldtk` provides support for the latest LDTK schema version (for a value that also includes N-1, as
+there may be some time lag between the latest LDTK version being published and a new version of `micro_ldtk` being
+published)
+
+To either support a different LDTK schema version, or to pin your version, you will need to disable default features and
+select the schema version you need:
+
+```toml
+[dependencies]
+micro_ldtk = { version = "0.1.0", default-features = false, features = ["ldtk_1_2_5", "autotile"] }
+```
+
+### Features
+
+- `autotile`: Provides type conversions from LDTK projects to [micro_autotile](https://crates.io/crates/micro_autotile) `AutoRuleSet` structs. Re-exports `micro_autotile` as `autotile`.
+- `ldtk_1_2_5`: Provides support for LDTK schema version 1.2.5
+- `ldtk_1_2_4`: Provides support for LDTK schema version 1.2.4
+- `no_panic`: Replaces explicit `panic!` calls (unwrap, expect, panic, etc) with aborts. This can reduce WASM binary size, but may not cover all areas. PRs welcome.
+
+## Usage
+
+First, include the plugin in your app. This will include an asset loader for LDTK files, and will create resources for indexed levels and tilesets.
+In the context of this README, "tilesets" refers to the _metadata associated with tile IDs_, and not the spritesheets or images that might be rendered
+to represent the tile ID.
+
+Levels and tilesets must have globally unique names, or the last one loaded will be used.
+
+```rust
+use bevy::prelude::*;
+use micro_ldtk::MicroLDTKPlugin;
+
+fn main() {
+    App::build()
+        .add_plugins(DefaultPlugins)
+        .add_plugin(MicroLDTKPlugin)
+        .run();
+}
+```
+
+Elsewhere, load one or more LDTK projects through the asset server:
+
+```rust
+use bevy::prelude::*;
+use micro_ldtk::Project;
+
+#[derive(Resource, Debug)]
+pub struct MyLdtkProject(Handle<Project>);
+
+pub fn startup(
+    mut commands: Commands,
+    asset_server: Res<AssetServer>,
+) {
+    let project: Handle<Project> = asset_server.load("path/to/project.ldtk");
+    commands.insert_resource(MyLdtkProject(project));
+}
+```
+
+When LDTK projects are loaded or modified (when asset events are enabled), the levels and tilesets will be parsed into
+a more ergonomic format, and stored in resources. These resources can be accessed through the `LevelIndex` and `TilesetIndex` resources.
+
+```rust
+use bevy::prelude::*;
+use micro_ldtk::{LevelIndex, TilesetIndex};
+
+pub fn process_some_level(
+    level_index: Res<LevelIndex>,
+    tileset_index: Res<TilesetIndex>,
+) {
+    let level = level_index.get("level_name").unwrap();
+    let tileset = tileset_index.get("tileset_name").unwrap();
+
+    for layer in level.layers() {
+        layer.for_each_tile(|x, y, tile_data| {
+            let tile_metadata = tileset.get(tile_data.gid());
+            log::info!("Got tile {:?} at [{}, {}]", tile_metadata, x, y);
+        });
+    }
+}
+```
\ No newline at end of file