diff --git a/engine/samples/CMakeLists.txt b/engine/samples/CMakeLists.txt
index db72823397..8385590cfe 100644
--- a/engine/samples/CMakeLists.txt
+++ b/engine/samples/CMakeLists.txt
@@ -33,6 +33,7 @@ macro(make_sample)
     endif()
 endmacro()
 # Add samples
+make_sample(DIR "audio" ASSETS)
 make_sample(DIR "hello-cubos")
 make_sample(DIR "settings")
 make_sample(DIR "events")
diff --git a/engine/samples/audio/assets/bg_music.mp3 b/engine/samples/audio/assets/bg_music.mp3
new file mode 100644
index 0000000000..688585bef0
Binary files /dev/null and b/engine/samples/audio/assets/bg_music.mp3 differ
diff --git a/engine/samples/audio/assets/bg_music.mp3.meta b/engine/samples/audio/assets/bg_music.mp3.meta
new file mode 100644
index 0000000000..dd5bdcaa5f
--- /dev/null
+++ b/engine/samples/audio/assets/bg_music.mp3.meta
@@ -0,0 +1,3 @@
+{
+    "id": "059c16e7-a439-44c7-9bdc-7f133dba0c80"
+}
diff --git a/engine/samples/audio/assets/input.bind b/engine/samples/audio/assets/input.bind
new file mode 100644
index 0000000000..18a3fecc3c
--- /dev/null
+++ b/engine/samples/audio/assets/input.bind
@@ -0,0 +1,13 @@
+{
+	"actions": {
+		"skip": [
+			{"keys": ["Return"]}
+		],
+		"play_pause": [
+			{"keys": ["Space"]}
+		],
+		"stop": [
+			{"keys": ["BackSpace"]}
+		]
+	}
+}
diff --git a/engine/samples/audio/assets/input.bind.meta b/engine/samples/audio/assets/input.bind.meta
new file mode 100644
index 0000000000..813969c690
--- /dev/null
+++ b/engine/samples/audio/assets/input.bind.meta
@@ -0,0 +1,3 @@
+{
+	"id": "6709a9ce-8651-4295-bdf2-848b052ce1f7"
+}
diff --git a/engine/samples/audio/assets/medieval_fanfare.wav b/engine/samples/audio/assets/medieval_fanfare.wav
new file mode 100644
index 0000000000..d961da7227
Binary files /dev/null and b/engine/samples/audio/assets/medieval_fanfare.wav differ
diff --git a/engine/samples/audio/assets/medieval_fanfare.wav.meta b/engine/samples/audio/assets/medieval_fanfare.wav.meta
new file mode 100644
index 0000000000..af052bba40
--- /dev/null
+++ b/engine/samples/audio/assets/medieval_fanfare.wav.meta
@@ -0,0 +1,3 @@
+{
+	"id": "3f93e774-888c-4ead-8819-67fc7e873df0"
+}
diff --git a/engine/samples/audio/assets/sample1.flac b/engine/samples/audio/assets/sample1.flac
new file mode 100644
index 0000000000..6cdf25779e
Binary files /dev/null and b/engine/samples/audio/assets/sample1.flac differ
diff --git a/engine/samples/audio/assets/sample1.flac.meta b/engine/samples/audio/assets/sample1.flac.meta
new file mode 100644
index 0000000000..37412e42ae
--- /dev/null
+++ b/engine/samples/audio/assets/sample1.flac.meta
@@ -0,0 +1,3 @@
+{
+	"id": "ccf3b646-1307-430d-bf3e-a23e06430043"
+}
diff --git a/engine/samples/audio/main.cpp b/engine/samples/audio/main.cpp
new file mode 100644
index 0000000000..78b9d151b0
--- /dev/null
+++ b/engine/samples/audio/main.cpp
@@ -0,0 +1,120 @@
+#include <cubos/engine/assets/plugin.hpp>
+#include <cubos/engine/audio/plugin.hpp>
+#include <cubos/engine/collisions/plugin.hpp>
+#include <cubos/engine/fixed_step/plugin.hpp>
+#include <cubos/engine/input/plugin.hpp>
+#include <cubos/engine/physics/plugin.hpp>
+#include <cubos/engine/render/camera/camera.hpp>
+#include <cubos/engine/render/camera/draws_to.hpp>
+#include <cubos/engine/render/camera/perspective.hpp>
+#include <cubos/engine/render/defaults/plugin.hpp>
+#include <cubos/engine/render/defaults/target.hpp>
+#include <cubos/engine/settings/plugin.hpp>
+#include <cubos/engine/settings/settings.hpp>
+#include <cubos/engine/transform/plugin.hpp>
+#include <cubos/engine/window/plugin.hpp>
+
+#include "cubos/core/tel/logging.hpp"
+#include "cubos/engine/audio/pause.hpp"
+#include "cubos/engine/audio/play.hpp"
+#include "cubos/engine/audio/stop.hpp"
+
+using namespace cubos::engine;
+
+/// [Get handles to assets]
+static const Asset<Audio> AudioAssetMP3 = AnyAsset("059c16e7-a439-44c7-9bdc-7f133dba0c80");
+static const Asset<Audio> AudioAssetWAV = AnyAsset("3f93e774-888c-4ead-8819-67fc7e873df0");
+static const Asset<Audio> AudioAssetFLAC = AnyAsset("ccf3b646-1307-430d-bf3e-a23e06430043");
+static const Asset<InputBindings> BindingsAsset = AnyAsset("6709a9ce-8651-4295-bdf2-848b052ce1f7");
+static const std::array<Asset<Audio>, 3> AudioAssets = {AudioAssetMP3, AudioAssetWAV, AudioAssetFLAC};
+/// [Get handles to assets]
+
+int main(int argc, char** argv)
+{
+    Cubos cubos{argc, argv};
+
+    size_t currAsset = 0;
+
+    cubos.plugin(settingsPlugin);
+    cubos.plugin(windowPlugin);
+    cubos.plugin(transformPlugin);
+    cubos.plugin(fixedStepPlugin);
+    cubos.plugin(assetsPlugin);
+    cubos.plugin(renderDefaultsPlugin);
+    cubos.plugin(collisionsPlugin);
+    cubos.plugin(physicsPlugin);
+    cubos.plugin(inputPlugin);
+    cubos.plugin(audioPlugin);
+
+    cubos.startupSystem("configure Assets").before(settingsTag).call([](Settings& settings) {
+        settings.setString("assets.app.osPath", APP_ASSETS_PATH);
+        settings.setString("assets.builtin.osPath", BUILTIN_ASSETS_PATH);
+    });
+
+    cubos.startupSystem("load and set the Input Bindings")
+        .tagged(assetsTag)
+        .call([](const Assets& assets, Input& input) {
+            auto bindings = assets.read<InputBindings>(BindingsAsset);
+            input.bind(*bindings);
+        });
+
+    cubos.startupSystem("create a camera").call([](Commands cmds) {
+        auto targetEnt = cmds.create().add(RenderTargetDefaults{}).entity();
+
+        cmds.create()
+            .relatedTo(targetEnt, DrawsTo{})
+            .add(Camera{.zNear = 0.1F, .zFar = 1000.0F})
+            .add(PerspectiveCamera{.fovY = 60.0F})
+            .add(Position{{0.0F, 0.0F, 0.0F}})
+            .add(Rotation::lookingAt({-1.0F, -1.0F, -1.0F}, glm::vec3{0.0F, 1.0F, 0.0F}))
+            .add(AudioListener{true});
+    });
+
+    cubos.startupSystem("create an audio source").after(audioStateInitTag).call([](Commands cmds) {
+        cmds.create()
+            .add(Position{{0.0F, 0.0F, 0.0F}})
+            .add(Velocity{.vec = {1.0F, 1.0F, 1.0F}})
+            .add(Rotation::lookingAt({-1.0F, -1.0F, -1.0F}, glm::vec3{0.0F, 1.0F, 0.0F}))
+            .add(AudioSource{});
+    });
+
+    cubos.system("play audio").call([&currAsset](Input& input, Commands cmds, Query<Entity, AudioSource&> query) {
+        for (auto [ent, src] : query)
+        {
+            if (src.sound.isNull())
+            {
+                src.sound = AudioAssets[0];
+                cmds.add(ent, AudioPlay{});
+            }
+
+            if (input.justPressed("skip"))
+            {
+                CUBOS_INFO("SKIP: {}", src.sound.getIdString());
+                cmds.add(ent, AudioStop{});
+                src.sound = AudioAssets[++currAsset % 3];
+                CUBOS_INFO("PLAYING: {}", src.sound.getIdString());
+                cmds.add(ent, AudioPlay{});
+            }
+            if (input.justPressed("play_pause"))
+            {
+                if (src.playing)
+                {
+                    cmds.add(ent, AudioPause{});
+                    CUBOS_INFO("PAUSING: {}", src.sound.getIdString());
+                }
+                else
+                {
+                    cmds.add(ent, AudioPlay{});
+                    CUBOS_INFO("PLAYING: {}", src.sound.getIdString());
+                }
+            }
+            if (input.justPressed("stop"))
+            {
+                cmds.add(ent, AudioStop{});
+                CUBOS_INFO("STOPPING: {}", src.sound.getIdString());
+            }
+        }
+    });
+
+    cubos.run();
+}