Default scene API idea
diff --git a/include/rive/scene.hpp b/include/rive/scene.hpp
index 90de466..a30da58 100644
--- a/include/rive/scene.hpp
+++ b/include/rive/scene.hpp
@@ -51,6 +51,8 @@
         virtual SMIBool* getBool(const std::string&) const;
         virtual SMINumber* getNumber(const std::string&) const;
         virtual SMITrigger* getTrigger(const std::string&) const;
+
+        static std::unique_ptr<Scene> importDefault(Span<uint8_t>, Factory*);
     };
 
 } // namespace rive
diff --git a/src/scene_default.cpp b/src/scene_default.cpp
new file mode 100644
index 0000000..e85a7b4
--- /dev/null
+++ b/src/scene_default.cpp
@@ -0,0 +1,58 @@
+#include "rive/artboard.hpp"
+#include "rive/file.hpp"
+#include "rive/scene.hpp"
+
+using namespace rive;
+
+class SelfContainedScene : public Scene {
+    std::unique_ptr<File> m_File;
+    std::unique_ptr<ArtboardInstance> m_ABI;
+    std::unique_ptr<Scene> m_Scene;
+
+public:
+    SelfContainedScene(std::unique_ptr<File> file,
+                       std::unique_ptr<ArtboardInstance> abi,
+                       std::unique_ptr<Scene> scene)
+        : Scene(abi.get())
+        , m_File(std::move(file))
+        , m_ABI(std::move(abi))
+        , m_Scene(std::move(scene)) {}
+
+    ~SelfContainedScene() = default;
+
+    // Forward to our m_Scene
+
+    std::string name() const { return m_Scene->name(); }
+    Loop loop() const { return m_Scene->loop(); }
+    bool isTranslucent() const { return m_Scene->isTranslucent(); }
+    float durationSeconds() const { return m_Scene->durationSeconds(); }
+
+    bool advanceAndApply(float seconds) { return m_Scene->advanceAndApply(seconds); }
+    void draw(Renderer* renderer) { return m_Scene->draw(renderer); }
+
+    void pointerDown(Vec2D pos) { return m_Scene->pointerDown(pos); }
+    void pointerMove(Vec2D pos) { return m_Scene->pointerMove(pos); }
+    void pointerUp(Vec2D pos) { return m_Scene->pointerUp(pos); }
+
+    size_t inputCount() const { return m_Scene->inputCount(); }
+    SMIInput* input(size_t index) const { return m_Scene->input(index); }
+    SMIBool* getBool(const std::string& name) const { return m_Scene->getBool(name); }
+    SMINumber* getNumber(const std::string& name) const { return m_Scene->getNumber(name); }
+    SMITrigger* getTrigger(const std::string& name) const { return m_Scene->getTrigger(name); }
+};
+
+std::unique_ptr<Scene> Scene::importDefault(Span<uint8_t> span, Factory* factory) {
+    auto file = File::import(span, factory);
+    if (file) {
+        auto abi = file->artboardDefault();
+        if (abi) {
+            auto scene = abi->defaultScene();
+            if (scene) {
+                return std::make_unique<SelfContainedScene>(std::move(file),
+                                                            std::move(abi),
+                                                            std::move(scene));
+            }
+        }
+    }
+    return nullptr;
+}
\ No newline at end of file
diff --git a/test/default_state_machine_test.cpp b/test/default_state_machine_test.cpp
index bfe7d1a..54bae7d 100644
--- a/test/default_state_machine_test.cpp
+++ b/test/default_state_machine_test.cpp
@@ -29,3 +29,9 @@
     REQUIRE(scene != nullptr);
     REQUIRE(scene->name() == smi->name());
 }
+
+TEST_CASE("load default scene", "[file]") {
+    auto bytes = ReadFile("../../test/assets/entry.riv");
+    auto scene = rive::Scene::importDefault(rive::toSpan(bytes), &rive::gNoOpFactory);
+    REQUIRE(scene.get());
+}
\ No newline at end of file
diff --git a/test/rive_file_reader.hpp b/test/rive_file_reader.hpp
index 1076359..f06dd6e 100644
--- a/test/rive_file_reader.hpp
+++ b/test/rive_file_reader.hpp
@@ -6,16 +6,9 @@
 #include "no_op_factory.hpp"
 #include "../src/render_counter.hpp"
 
-static inline std::unique_ptr<rive::File>
-ReadRiveFile(const char path[],
-             rive::Factory* factory = nullptr,
-             rive::FileAssetResolver* resolver = nullptr) {
-    if (!factory) {
-        factory = &rive::gNoOpFactory;
-    }
-
+static inline std::vector<uint8_t> ReadFile(const char path[]) {
     FILE* fp = fopen(path, "rb");
-    REQUIRE(fp != nullptr);
+    REQUIRE(fp);
 
     fseek(fp, 0, SEEK_END);
     const size_t length = ftell(fp);
@@ -24,6 +17,19 @@
     REQUIRE(fread(bytes.data(), 1, length, fp) == length);
     fclose(fp);
 
+    return bytes;
+}
+
+static inline std::unique_ptr<rive::File>
+ReadRiveFile(const char path[],
+             rive::Factory* factory = nullptr,
+             rive::FileAssetResolver* resolver = nullptr) {
+    if (!factory) {
+        factory = &rive::gNoOpFactory;
+    }
+    
+    auto bytes = ReadFile(path);
+
     rive::ImportResult result;
     auto file = rive::File::import(rive::toSpan(bytes), factory, &result, resolver);
     REQUIRE(result == rive::ImportResult::success);