diff --git a/README.md b/README.md
index f8392abe0d422840d1cb7311fd16f6fe94d661c4..1dc30287f597edf5d7fc0391603ff5ae5588774c 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # Micro Game Macros
 
-![docs.rs](https://img.shields.io/docsrs/micro_game_macros?style=for-the-badge)
-![Crates.io](https://img.shields.io/crates/v/micro_game_macros?style=for-the-badge)
+[![docs.rs](https://img.shields.io/docsrs/micro_games_macros?style=for-the-badge)](https://docs.rs/micro_games_macros)
+[![Crates.io](https://img.shields.io/crates/v/micro_games_macros?style=for-the-badge)](https://crates.io/crates/micro_games_macros)
 
 A collection of utility macros for building games
 
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000000000000000000000000000000000000..a6986e3a04e432ea56dc45a8cb15b7f05093e00b
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,3 @@
+hard_tabs = true
+use_field_init_shorthand = true
+use_try_shorthand = true
diff --git a/src/lib.rs b/src/lib.rs
index d4b5c21763f15f7ca44be76682561d625136f5b5..e58555f28ec3b19bf3237285dd1ee5f904d47714 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,97 @@
+//! A collection of complimentary utility macros for building games
+//!
+//! Use the [asset_system] macro to create a set of types that manage loading assets, and then
+//! derive [JsonLoader] for any asset type to create a flexible resource loader that links in
+//! to the generated asset system
+//!
+//! ```rust
+//! use bevy::prelude::{App, DefaultPlugins, Image, Plugin, Res, ResMut, Resource, Assets, TextureAtlas};
+//! use bevy::reflect::{TypePath, TypeUuid};
+//! use micro_games_macros::{asset_system, JsonLoader};
+//! use serde::{Deserialize, Serialize};
+//!
+//! // We can customise the properties on the "asset loader" type that the
+//! // macro generates by adding "loader_property" annotations. The parameter
+//! // to this macro is simple any property declaration that could be added to
+//! // a regular type that derives SystemParam (including lifetimes)
+//!
+//! #[asset_system]
+//! #[loader_property(pub sheets: ResMut<'w, Assets<TextureAtlas>>)]
+//! pub struct AssetHandles {
+//!     // For non-JsonLoader assets, you just need to specify a name -> AssetType property.
+//!     // The generated asset handles type will contain a hashmap of name -> Handle<AssetType>
+//!     // under the property name specified. Loading functions such as load_asset_name will
+//!     // be created on the loading type, where the first parameter is the path and the second
+//!     // parameter is the asset name that will be used in the hashmap for later retrieval of
+//!     // the asset
+//!     images: Image,
+//!     // To use an asset_system with a JsonLoader, you will need to add entries for both the
+//!     // asset itself and its index type (generated by JsonLoader). Specific instances of
+//!     // an asset are stored under the Item type (no suffix), keyed in the handle map by their
+//!     // ID property. The index generated from each file (a map of ID -> Item) is stored under
+//!     // the Index type (type name: AssetName + Index), keyed by the name provided when loading
+//!     // the asset
+//!     some_resource: MyCoolResource,
+//!     // The property names generate load functions, but don't have to match the name of the
+//!     // resource being loaded. Index & Item types for a JsonLoader resource can have their
+//!     // names specified as part of the JsonLoader derive
+//!     some_index_of_resources: MyCoolResourceIndex,
+//! }
+//!
+//! #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize)]
+//! #[loader(extension = "mcr", uuid = "00000000-0000-0000-0000-000000000000",
+//!      asset_name = some_resource, index_name = some_index_of_resources)]
+//! #[uuid = "10000000-0000-0000-0000-000000000001"]
+//! pub struct MyCoolResource {
+//!     // You must include exactly one of either a property named "id", or another property annotated
+//!     // with the "asset_id" attribute.
+//!     #[asset_id]
+//!     some_identifier: String,
+//!     foo: usize,
+//!     bar: bool,
+//! }
+//!
+//! // The asset system generates a system param for scheduling the load of an asset. It uses bevy's
+//! // asset server, which makes the system compatible with plugins such as bevy_embedded_assets
+//! pub fn loading_system(mut loader: AssetHandlesLoader) {
+//!     // The loader contains a number of functions for loading either individual assets
+//!     // (two parameters, path and id), or a series of assets (a single parameter, a vector
+//!     // of tuples each denoting path and id)
+//! 	loader.load_images("path/to/my_image.png", "my_image");
+//!
+//!     // JsonLoader assets require the use of the Index type to correctly load them, even for
+//!     // files that only contain one object instance. The identifier (either id or asset_id)
+//!     // will be used to add each instance of an asset to the Item type map
+//!     loader.load_some_index_of_resources("path/to/my_asset.mcr", "my_asset");
+//! }
+//!
+//! pub fn use_asset_system(assets: Res<AssetHandles>) {
+//!     // JsonLoader assets can be accessed through the item type functions. These functions
+//!     // provide a weak handle to the asset, meaning that the assets will usually unload
+//!     // if removed from the AssetHandles type unless another strong handle was created externally
+//!     let some_resource_handle = assets.some_resource("the_asset_id");
+//!
+//!     // The handle functions exactly match the name of the asset property in the originally
+//!     // defined struct
+//!     let image_handle = assets.images("my_image");
+//! }
+//!
+//! pub struct AssetSystemPlugin;
+//! impl Plugin for AssetSystemPlugin {
+//!     fn build(&self, app: &mut App) {
+//!         app.init_resource::<AssetHandles>()
+//!             // JsonLoader will create a plugin that wraps all of the functionality for a single
+//!             // asset type, including loaders and hot reload support
+//!             .add_plugins(MyCoolResourcePlugin);
+//!     }
+//! }
+//!
+//! fn main() {
+//!     let app = App::new()
+//!         .add_plugins((DefaultPlugins, AssetSystemPlugin));
+//! }
+//! ```
+
 use proc_macro::TokenStream;
 
 use syn::{parse_macro_input, DeriveInput};
@@ -42,22 +136,22 @@ pub(crate) mod std_traits;
 ///
 /// #[derive(Resource)]
 /// pub struct AssetHandles {
-///   simple_asset: HashMap<String, Handle<SimpleAsset>>,
-///   simple_asset_index: HashMap<String, Handle<SimpleAssetIndex>>,
+///     simple_asset: HashMap<String, Handle<SimpleAsset>>,
+///     simple_asset_index: HashMap<String, Handle<SimpleAssetIndex>>,
 /// }
 ///
 /// #[derive(JsonLoader, TypePath, TypeUuid, Serialize, Deserialize)]
 /// #[loader(extension = "satt", uuid = "00000000-0000-0000-0000-000000000000")]
 /// #[uuid = "00000000-0000-0000-0000-000000000001"]
 /// pub struct SimpleAsset {
-///   id: String,
-///   widget: usize,
+///     id: String,
+///     widget: usize,
 /// }
 ///
 /// fn main() {
-///   bevy::app::App::new()
-///     .add_plugins(bevy::prelude::DefaultPlugins)
-///     .add_plugins(SimpleAssetPlugin);
+///     bevy::app::App::new()
+///         .add_plugins(bevy::prelude::DefaultPlugins)
+///         .add_plugins(SimpleAssetPlugin);
 /// }
 /// ```
 ///
@@ -79,26 +173,26 @@ pub(crate) mod std_traits;
 /// )]
 /// #[uuid = "00000000-0000-0000-0000-000000000001"]
 /// pub struct MyAsset {
-///   /// The asset identifier needs to implement [std::fmt::Display]
-///   #[asset_id]
-///   uniq_ident: usize,
+///     /// The asset identifier needs to implement [std::fmt::Display]
+///     #[asset_id]
+///     uniq_ident: usize,
 /// }
 ///
 /// pub mod inner_module {
 /// #  use bevy::prelude::{Handle, Resource};
 /// #  use std::collections::HashMap;
-///   
-///   #[derive(Resource)]
-///   pub struct SimpleAssetLocator {
-///     pub some_asset_prop: HashMap<String, Handle<super::MyAsset>>,
-///     pub set_of_assets: HashMap<String, Handle<super::MyAssetIndex>>,
-///   }
+///
+///     #[derive(Resource)]
+///     pub struct SimpleAssetLocator {
+///         pub some_asset_prop: HashMap<String, Handle<super::MyAsset>>,
+///         pub set_of_assets: HashMap<String, Handle<super::MyAssetIndex>>,
+///     }
 /// }
 ///
 /// fn main() {
-///   bevy::app::App::new()
-///     .add_plugins(bevy::prelude::DefaultPlugins)
-///     .add_plugins(MyAssetPlugin);
+///     bevy::app::App::new()
+///         .add_plugins(bevy::prelude::DefaultPlugins)
+///         .add_plugins(MyAssetPlugin);
 /// }
 /// ```
 #[proc_macro_derive(JsonLoader, attributes(loader, asset_id))]
@@ -120,14 +214,14 @@ pub fn json_loader(input: TokenStream) -> TokenStream {
 ///
 /// #[asset_system]
 /// pub struct AssetHandles {
-///   my_asset: Image,
+///     my_asset: Image,
 /// }
 ///
 /// pub fn loading_system(mut loader: AssetHandlesLoader) {
-///   loader.load_my_asset("path/to/asset.png", "Asset");
+///     loader.load_my_asset("path/to/asset.png", "Asset");
 /// }
 /// pub fn use_asset_system(assets: Res<AssetHandles>) {
-///   let handle = assets.my_asset("Asset");
+///     let handle = assets.my_asset("Asset");
 /// }
 /// ```
 ///
@@ -139,17 +233,17 @@ pub fn json_loader(input: TokenStream) -> TokenStream {
 ///
 /// #[asset_system]
 /// pub struct AssetHandles {
-///   image: Image,
-///   #[skip]
-///   spritesheet: TextureAtlas
+///     image: Image,
+///     #[skip]
+///     spritesheet: TextureAtlas,
 /// }
 ///
-/// impl <'w>AssetHandlesLoader<'w> {
-///   pub fn load_spritesheet(&mut self, path: String, name: String) {
-///     let image_handle = self.load_image(path, name.clone());
-///     // let sheet_handle = .. more code ..
-///     // self.spritesheet.insert(name, sheet_handle);
-///   }
+/// impl<'w> AssetHandlesLoader<'w> {
+///     pub fn load_spritesheet(&mut self, path: String, name: String) {
+///         let image_handle = self.load_image(path, name.clone());
+///         // let sheet_handle = .. more code ..
+///         // self.spritesheet.insert(name, sheet_handle);
+///     }
 /// }
 /// ```
 ///
@@ -157,34 +251,36 @@ pub fn json_loader(input: TokenStream) -> TokenStream {
 /// The included property must be a `SystemParam`, and has access to the `'w` lifetime
 ///
 /// ```rust
-/// use bevy::prelude::{EventWriter, Event, Image, TextureAtlas, Assets, ResMut, Vec2, Handle};
+/// use bevy::prelude::{Assets, Event, EventWriter, Handle, Image, ResMut, TextureAtlas, Vec2};
 /// use micro_games_macros::{asset_system, loader_property};
 ///
 /// #[derive(Event)]
 /// pub struct LoadingEvent {
-///   pub event_id: usize,
+///     pub event_id: usize,
 /// }
 ///
 /// #[asset_system]
 /// #[loader_property(pub load_events: EventWriter<'w, LoadingEvent>)]
 /// #[loader_property(pub sheets: ResMut<'w, Assets<TextureAtlas>>)]
 /// pub struct AssetHandles {
-///   image: Image,
-///   #[skip]
-///   spritesheet: TextureAtlas
+///     image: Image,
+///     #[skip]
+///     spritesheet: TextureAtlas,
 /// }
 ///
-/// impl <'w>AssetHandlesLoader<'w> {
-///   pub fn load_spritesheet(&mut self, path: String, name: String) -> Handle<TextureAtlas> {
-///     let image_handle = self.load_image(path, name.clone());
-///     let sheet = TextureAtlas::new_empty(image_handle, Vec2::ZERO);
-///     let sheet_handle = self.sheets.add(sheet);
-///
-///     self.storage.spritesheet.insert(name.clone(), sheet_handle.clone());
-///     self.load_events.send(LoadingEvent { event_id: 123 });
-///     
-///     sheet_handle
-///   }
+/// impl<'w> AssetHandlesLoader<'w> {
+///     pub fn load_spritesheet(&mut self, path: String, name: String) -> Handle<TextureAtlas> {
+///         let image_handle = self.load_image(path, name.clone());
+///         let sheet = TextureAtlas::new_empty(image_handle, Vec2::ZERO);
+///         let sheet_handle = self.sheets.add(sheet);
+///
+///         self.storage
+///             .spritesheet
+///             .insert(name.clone(), sheet_handle.clone());
+///         self.load_events.send(LoadingEvent { event_id: 123 });
+///
+///         sheet_handle
+///     }
 /// }
 /// ```
 #[proc_macro_attribute]
@@ -240,7 +336,7 @@ pub fn derive_kayak_wigdet(input: TokenStream) -> TokenStream {
 ///
 /// #[derive(PartialEq, Eq, Debug, FromInner)]
 /// struct MyValue {
-///   foo_bar: usize,
+///     foo_bar: usize,
 /// }
 ///
 /// let value = MyValue::from(2000);