diff --git a/.gitignore b/.gitignore
index 448668577b5a00ec14ce582567753b185de56bd8..a89933bfd13b47b74cf2639a2addb00f9b10e511 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,6 @@ Cargo.lock
 
 # These are backup files generated by rustfmt
 **/*.rs.bk
+
+# IDE Files
+.idea
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..b07f6a589cbecc175f7ab52feac49d709bd2e685
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "micro_bevy_musicbox"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+bevy = { version = "0.7", default-features = false }
+bevy_kira_audio = { version = "0.10", features = ["mp3"] }
+serde = "1"
+serde_json = "1"
\ No newline at end of file
diff --git a/rust-toolchain.toml b/rust-toolchain.toml
new file mode 100644
index 0000000000000000000000000000000000000000..271800cb2f3791b3adc24328e71c9e2550b439db
--- /dev/null
+++ b/rust-toolchain.toml
@@ -0,0 +1,2 @@
+[toolchain]
+channel = "nightly"
\ No newline at end of file
diff --git a/rustfmt.toml b/rustfmt.toml
new file mode 100644
index 0000000000000000000000000000000000000000..ddac46a818a71283d5b1d79d0d01761aaceb5b84
--- /dev/null
+++ b/rustfmt.toml
@@ -0,0 +1,4 @@
+hard_tabs = true
+group_imports = "StdExternalCrate"
+use_field_init_shorthand = true
+use_try_shorthand = true
\ No newline at end of file
diff --git a/src/channels.rs b/src/channels.rs
new file mode 100644
index 0000000000000000000000000000000000000000..dd056a2dbc33d1b5e3c0ebd6971c8ed34a9d64db
--- /dev/null
+++ b/src/channels.rs
@@ -0,0 +1,23 @@
+/// The first channel to use for main music tracks. Combined with
+/// `music audio channel b` to perform cross-fades
+/// *Volume Type:* Music
+pub struct MusicAudioChannelA;
+/// The backup channel to use for main music tracks. Combined with
+/// `music audio channel a` to perform cross-fades
+/// *Volume Type:* Music
+pub struct MusicAudioChannelB;
+/// The first channel to use for background ambiance tracks.
+/// Combined with `ambiance audio channel b` to perform cross-fades
+/// *Volume Type:* SFX
+pub struct AmbianceAudioChannelA;
+/// The backup channel to use for background ambiance tracks.
+/// Combined with `ambiance audio channel a` to perform cross-fades
+/// *Volume Type:* SFX
+pub struct AmbianceAudioChannelB;
+/// The channel used for generic sound effects, such as spells, hits,
+/// attacks, etc.
+/// *Volume Type:* SFX
+pub struct SfxAudioChannel;
+/// The channel used for any UI related sound effects
+/// *Volume Type:* UI SFX
+pub struct UiSfxAudioChannel;
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..28a8637fa49144ea618d86300d2ea70c51deab5b
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,41 @@
+use bevy::app::{App, Plugin, PluginGroup, PluginGroupBuilder};
+use bevy_kira_audio::{AudioApp, AudioPlugin};
+
+use crate::channels::{
+	AmbianceAudioChannelA, AmbianceAudioChannelB, MusicAudioChannelA, MusicAudioChannelB,
+	SfxAudioChannel, UiSfxAudioChannel,
+};
+use crate::utilities::{AudioCrossFade, AudioSettings};
+
+pub mod channels;
+pub mod music_box;
+pub mod utilities;
+
+pub mod prelude {
+	pub use super::channels::*;
+	pub use super::music_box::MusicBox;
+	pub use bevy_kira_audio::{AudioSource, AudioChannel};
+}
+
+pub struct MusicBoxPlugin;
+
+impl Plugin for MusicBoxPlugin {
+	fn build(&self, app: &mut App) {
+		app.add_audio_channel::<MusicAudioChannelA>()
+			.add_audio_channel::<MusicAudioChannelB>()
+			.add_audio_channel::<AmbianceAudioChannelA>()
+			.add_audio_channel::<AmbianceAudioChannelB>()
+			.add_audio_channel::<SfxAudioChannel>()
+			.add_audio_channel::<UiSfxAudioChannel>()
+			.insert_resource(AudioSettings::default())
+			.insert_resource(AudioCrossFade::default());
+	}
+}
+
+pub struct CombinedAudioPlugins;
+impl PluginGroup for CombinedAudioPlugins {
+	fn build(&mut self, group: &mut PluginGroupBuilder) {
+		group.add(AudioPlugin)
+			.add(MusicBoxPlugin);
+	}
+}
\ No newline at end of file
diff --git a/src/music_box.rs b/src/music_box.rs
new file mode 100644
index 0000000000000000000000000000000000000000..7647ff1f8ef33015cabee05b0bb6d2992ed86566
--- /dev/null
+++ b/src/music_box.rs
@@ -0,0 +1,124 @@
+use std::marker::PhantomData;
+
+use bevy::ecs::system::SystemParam;
+use bevy::prelude::*;
+use bevy_kira_audio::{AudioChannel, InstanceHandle};
+
+use crate::utilities::{AudioSettings, CrossFadeTrack, SuppliesAudio, TrackType};
+use crate::{
+	AmbianceAudioChannelA, AmbianceAudioChannelB, AudioCrossFade, MusicAudioChannelA,
+	MusicAudioChannelB, SfxAudioChannel, UiSfxAudioChannel,
+};
+
+#[derive(SystemParam)]
+pub struct AudioChannels<'w, 's> {
+	pub music_channel_a: Res<'w, AudioChannel<MusicAudioChannelA>>,
+	pub music_channel_b: Res<'w, AudioChannel<MusicAudioChannelB>>,
+	pub ambiance_channel_a: Res<'w, AudioChannel<AmbianceAudioChannelA>>,
+	pub ambiance_channel_b: Res<'w, AudioChannel<AmbianceAudioChannelB>>,
+	pub sfx_channel: Res<'w, AudioChannel<SfxAudioChannel>>,
+	pub ui_sfx_channel: Res<'w, AudioChannel<UiSfxAudioChannel>>,
+
+	#[system_param(ignore)]
+	_p: PhantomData<&'s ()>,
+}
+
+#[derive(SystemParam)]
+pub struct MusicBox<'w, 's, T: SuppliesAudio> {
+	pub commands: Commands<'w, 's>,
+	pub channels: AudioChannels<'w, 's>,
+	pub handles: Res<'w, T>,
+	pub settings: Res<'w, AudioSettings>,
+	pub fade_state: Res<'w, AudioCrossFade>,
+}
+
+pub enum MusicTrackState {
+	Pending,
+	Playing,
+	FadeOut { progress: f32 },
+	FadeIn { progress: f32 },
+	CrossFade { out_progress: f32, in_progress: f32 },
+}
+
+impl Default for MusicTrackState {
+	fn default() -> Self {
+		Self::Pending
+	}
+}
+
+impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
+	pub fn play_looped_music<Name: ToString>(&self, name: Name) -> Option<InstanceHandle> {
+		self.channels.music_channel_a.stop();
+		self.channels.music_channel_b.stop();
+
+		match self.resolve_track_name(name) {
+			TrackType::Single(track) => match self.fade_state.music.active {
+				CrossFadeTrack::A => Some(
+					self.channels
+						.music_channel_a
+						.play_looped(track.clone_weak()),
+				),
+				CrossFadeTrack::B => Some(
+					self.channels
+						.music_channel_b
+						.play_looped(track.clone_weak()),
+				),
+			},
+			TrackType::WithIntro(intro, looped) => match self.fade_state.music.active {
+				CrossFadeTrack::A => Some(
+					self.channels
+						.music_channel_a
+						.play_looped_with_intro(intro.clone_weak(), looped.clone_weak()),
+				),
+				CrossFadeTrack::B => Some(
+					self.channels
+						.music_channel_b
+						.play_looped_with_intro(intro.clone_weak(), looped.clone_weak()),
+				),
+			},
+			TrackType::Missing => None,
+		}
+	}
+
+	pub fn play_effect_once<Name: ToString>(&mut self, name: Name) -> Option<InstanceHandle> {
+		let name = name.to_string();
+
+		match self.handles.get_audio_track(&name) {
+			Some(track) => Some(self.channels.sfx_channel.play(track)),
+			None => None,
+		}
+	}
+
+	pub fn play_ambiance<Name: ToString>(&self, name: Name) -> Option<InstanceHandle> {
+		self.channels.ambiance_channel_a.stop();
+		self.channels.ambiance_channel_b.stop();
+
+		match self.resolve_track_name(name) {
+			TrackType::Single(track) => match self.fade_state.ambiance.active {
+				CrossFadeTrack::A => Some(
+					self.channels
+						.ambiance_channel_a
+						.play_looped(track.clone_weak()),
+				),
+				CrossFadeTrack::B => Some(
+					self.channels
+						.ambiance_channel_b
+						.play_looped(track.clone_weak()),
+				),
+			},
+			TrackType::WithIntro(intro, looped) => match self.fade_state.ambiance.active {
+				CrossFadeTrack::A => Some(
+					self.channels
+						.ambiance_channel_a
+						.play_looped_with_intro(intro.clone_weak(), looped.clone_weak()),
+				),
+				CrossFadeTrack::B => Some(
+					self.channels
+						.ambiance_channel_b
+						.play_looped_with_intro(intro.clone_weak(), looped.clone_weak()),
+				),
+			},
+			TrackType::Missing => None,
+		}
+	}
+}
diff --git a/src/utilities.rs b/src/utilities.rs
new file mode 100644
index 0000000000000000000000000000000000000000..76f085a98404949d11febc549bab52272fe952bd
--- /dev/null
+++ b/src/utilities.rs
@@ -0,0 +1,84 @@
+use bevy::ecs::system::Resource;
+use bevy::prelude::*;
+use bevy_kira_audio::AudioSource;
+use serde::{Deserialize, Serialize};
+
+use crate::music_box::MusicBox;
+
+pub trait SuppliesAudio: Resource {
+	fn get_audio_track<T: ToString>(&self, name: T) -> Option<Handle<AudioSource>>;
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
+pub struct AudioSettings {
+	master_volume: f32,
+	music_volume: f32,
+	sfx_volume: f32,
+	ui_volume: f32,
+}
+
+impl Default for AudioSettings {
+	fn default() -> Self {
+		Self {
+			master_volume: 1.0,
+			music_volume: 0.0,
+			sfx_volume: 0.0,
+			ui_volume: 0.0,
+		}
+	}
+}
+
+#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
+pub enum CrossFadeTrack {
+	#[default]
+	A,
+	B,
+}
+
+#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
+pub struct CrossFadeState {
+	pub active: CrossFadeTrack,
+	pub next: CrossFadeTrack,
+	pub progress: f32,
+}
+
+impl Default for CrossFadeState {
+	fn default() -> Self {
+		Self {
+			active: CrossFadeTrack::A,
+			next: CrossFadeTrack::B,
+			progress: 0.0,
+		}
+	}
+}
+
+#[derive(Copy, Clone, Debug, Default, Serialize, Deserialize)]
+pub struct AudioCrossFade {
+	pub music: CrossFadeState,
+	pub ambiance: CrossFadeState,
+}
+
+pub enum TrackType {
+	Single(Handle<AudioSource>),
+	WithIntro(Handle<AudioSource>, Handle<AudioSource>),
+	Missing,
+}
+
+impl<'w, 's, T: SuppliesAudio> MusicBox<'w, 's, T> {
+	pub fn resolve_track_name<Name: ToString>(&'w self, name: Name) -> TrackType {
+		let name = name.to_string();
+
+		if let (Some(intro), Some(looped)) = (
+			self.handles.get_audio_track(format!("{}_intro", &name)),
+			self.handles.get_audio_track(format!("{}_loop", &name)),
+		) {
+			TrackType::WithIntro(intro, looped)
+		} else if let Some(track) = self.handles.get_audio_track(name.clone()) {
+			TrackType::Single(track)
+		} else if let Some(track) = self.handles.get_audio_track(format!("{}_looped", name)) {
+			TrackType::Single(track)
+		} else {
+			TrackType::Missing
+		}
+	}
+}