diff --git a/src/Lib/AbstractDocument.hh b/src/Lib/AbstractDocument.hh
new file mode 100644
index 0000000000000000000000000000000000000000..495f6c172abc1e233dde8494dfc1d3b72b5532d8
--- /dev/null
+++ b/src/Lib/AbstractDocument.hh
@@ -0,0 +1,55 @@
+#ifndef VIVY_ABSTRACT_DOCUMENT_H
+#define VIVY_ABSTRACT_DOCUMENT_H
+
+#ifndef __cplusplus
+#error "This is a C++ header"
+#endif
+
+#include "Utils.hh"
+#include "Uuid.hh"
+#include <QFileInfo>
+#include <QDir>
+
+namespace Vivy
+{
+class AbstractDocument : public QObject {
+    Q_OBJECT
+    VIVY_UNMOVABLE_OBJECT(AbstractDocument)
+
+protected:
+    AbstractDocument() = default;
+
+    // Automate a part of the rename process, just need to provide a "success"
+    // callback and the new file info.
+    bool renameWith(const QFileInfo &newFile, auto success) noexcept
+    {
+        const QFileInfo oldFile(getName());
+
+        // Create folder if needed
+        QDir dirOp;
+        const QString newAbsDirPath = newFile.dir().absolutePath();
+        if (!dirOp.exists(newAbsDirPath)) {
+            qInfo() << "Create folder " << newAbsDirPath;
+            dirOp.mkpath(newAbsDirPath);
+        }
+
+        if (dirOp.rename(oldFile.absoluteFilePath(), newFile.absoluteFilePath())) {
+            success();
+            return true;
+        }
+
+        qCritical() << "Failed to rename" << oldFile << "to" << newFile;
+        return false;
+    }
+
+public:
+    virtual bool rename(const QString &) noexcept = 0;
+    virtual QString getName() const noexcept      = 0;
+    virtual Uuid getUuid() const noexcept         = 0;
+
+signals:
+    void documentChanged();
+};
+}
+
+#endif // VIVY_ABSTRACT_DOCUMENT_H
diff --git a/src/Lib/CRTPStore.hh b/src/Lib/CRTPStore.hh
new file mode 100644
index 0000000000000000000000000000000000000000..d75be68098041fe270faaf295d579e2e1b0b6996
--- /dev/null
+++ b/src/Lib/CRTPStore.hh
@@ -0,0 +1,72 @@
+#pragma once
+
+#ifndef __cplusplus
+#error "This is a C++ header"
+#endif
+
+#include "Utils.hh"
+#include "Uuid.hh"
+#include <QString>
+#include <QMap>
+#include <memory>
+
+#define VIVY_STORAGE_CLASS(theClassName, theDocumentName)                                          \
+    VIVY_UNMOVABLE_OBJECT(theClassName)                                                            \
+    friend CRTPStore<theClassName, theDocumentName>;
+
+namespace Vivy
+{
+// For example:
+// VivyDocumentStore final : public
+//      CRTPStore<VivyDocumentStore,    <- Child class
+//                VivyDocument>         <- Document type to hold
+template <class Store, class Document> class CRTPStore {
+    VIVY_UNMOVABLE_OBJECT(CRTPStore)
+
+protected:
+    QMap<Uuid, std::shared_ptr<Document>> documents{};
+    uint newDocumentNumber{ 1 };
+    static inline const QString newDocumentBaseName = QStringLiteral("Untitled ");
+
+protected:
+    explicit CRTPStore() noexcept = default;
+
+public:
+    // Load a document by its name
+    std::shared_ptr<Document> loadDocument(const QString &file)
+    {
+        auto ret      = std::make_shared<Document>(file);
+        const Uuid id = ret->getUuid();
+        documents[id] = ret;
+        return ret;
+    }
+
+    // Close a document, please be sure to not used any of the dangling
+    // references to the closed document...
+    void closeDocument(const Uuid &uuid) noexcept
+    {
+        auto *self = static_cast<Store *>(this);
+        self->documents.remove(uuid);
+    }
+
+    // Get stored documents
+    std::shared_ptr<Document> getDocument(const Uuid &uuid) const
+    {
+        auto *self = static_cast<Store *>(this);
+
+        if (!self->documents.contains(uuid)) {
+            qCritical() << "Couldn't find the document " << uuid;
+            throw std::runtime_error("Can't find the document");
+        }
+
+        return self->documents.value(uuid);
+    }
+
+    // Get to see if a document is already present or not
+    [[nodiscard("handle-it")]] bool isDocumentPresent(const Uuid &uuid) noexcept
+    {
+        auto *self = static_cast<Store *>(this);
+        return self->documents.count(uuid) >= 1;
+    }
+};
+}
diff --git a/src/Lib/Document/AbstractDocument.hh b/src/Lib/Document/AbstractDocument.hh
deleted file mode 100644
index 823a1a83a152f34ce73e4b96ceacdaccd9dc9b8c..0000000000000000000000000000000000000000
--- a/src/Lib/Document/AbstractDocument.hh
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef VIVY_ABSTRACT_DOCUMENT_H
-#define VIVY_ABSTRACT_DOCUMENT_H
-
-#ifndef __cplusplus
-#error "This is a C++ header"
-#endif
-
-#include "../Utils.hh"
-
-namespace Vivy
-{
-class AbstractDocument : public QObject {
-    Q_OBJECT
-    VIVY_UNMOVABLE_OBJECT(AbstractDocument)
-
-protected:
-    AbstractDocument()                   = default;
-    virtual ~AbstractDocument() noexcept = default;
-
-public:
-    virtual bool rename(const QString &) noexcept = 0;
-    virtual QString getName() const noexcept      = 0;
-
-signals:
-    void documentChanged();
-};
-}
-
-#endif // VIVY_ABSTRACT_DOCUMENT_H
diff --git a/src/Lib/Document/VivyDocument.cc b/src/Lib/Document/VivyDocument.cc
index ed8fbfc66a7cfeb545919b2f8ded803a823135d6..be9bc9fbbf57c6cf2c35d33a9e315ca40fd429ba 100644
--- a/src/Lib/Document/VivyDocument.cc
+++ b/src/Lib/Document/VivyDocument.cc
@@ -109,26 +109,12 @@ VivyDocument::rename(const QString &name) noexcept
     /* Compute new paths */
     const QString newNameWithExtension =
         name.right(filePrefix.size()) == filePrefix ? name : name + "." + filePrefix;
-    QFileInfo oldPath(documentLocation, documentName + "." + filePrefix);
-    QFileInfo newPath(documentLocation, newNameWithExtension);
-
-    /* Create folder if needed */
-    QDir dirOp;
-    const QString newAbsDirPath = newPath.dir().absolutePath();
-    if (!dirOp.exists(newAbsDirPath)) {
-        qInfo() << "Create folder " << newAbsDirPath;
-        dirOp.mkpath(newAbsDirPath);
-    }
+    const QFileInfo newPath(documentLocation, newNameWithExtension);
 
-    if (dirOp.rename(oldPath.absoluteFilePath(), newPath.absoluteFilePath())) {
+    return renameWith(newPath, [=, this]() noexcept -> void {
         documentLocation = newPath.dir();
         documentName     = newPath.baseName();
-        qDebug() << "Rename " << oldPath << " to " << newPath;
-        return true;
-    }
-
-    qCritical() << "Failed to rename " << oldPath << " to " << newPath;
-    return false;
+    });
 }
 
 std::shared_ptr<AudioSubDocument>
@@ -155,7 +141,7 @@ VivyDocument::getName() const noexcept
     return documentName;
 }
 
-VivyDocument::Uuid
+Uuid
 VivyDocument::getUuid() const noexcept
 {
     return uuid;
diff --git a/src/Lib/Document/VivyDocument.hh b/src/Lib/Document/VivyDocument.hh
index 9ecfbaa56c186cd73c677fb5ed0eb2e075a77495..eefaa11daa5eb8363c42a08bcaa1ce5c4d051f13 100644
--- a/src/Lib/Document/VivyDocument.hh
+++ b/src/Lib/Document/VivyDocument.hh
@@ -6,13 +6,13 @@
 #endif
 
 #include "../Utils.hh"
+#include "../AbstractDocument.hh"
+#include "../Uuid.hh"
 #include "CRTPSubDocument.hh"
-#include "AbstractDocument.hh"
 
 #include <memory>
 #include <QString>
 #include <QDir>
-#include <QUuid>
 #include <QJsonDocument>
 
 namespace Vivy
@@ -33,19 +33,6 @@ public:
         UntouchedByDefault = (1 << 1),
     };
 
-    class Uuid : public QUuid {
-    public:
-        explicit Uuid()
-            : QUuid(QUuid::createUuid())
-        {
-        }
-
-        QString toString() const noexcept
-        {
-            return QUuid::toString(Uuid::WithoutBraces);
-        };
-    };
-
     static inline const QString filePrefix{ "vivy" };
     static inline constexpr Utils::DocumentType type = Utils::DocumentType::Vivy;
 
@@ -71,7 +58,6 @@ private:
 public:
     // Create an empty document
     explicit VivyDocument(const QString &name, Options opt = NoOption);
-    ~VivyDocument() noexcept = default;
 
     bool rename(const QString &) noexcept override;
     bool loadSubDocument(const QString &) noexcept;
@@ -83,8 +69,8 @@ public:
     std::shared_ptr<AssSubDocument> getAssSubDocument() const noexcept;
 
     QString getName() const noexcept override;
-    Uuid getUuid() const noexcept;
     QString getDocumentCapabilitiesString() const noexcept;
+    Uuid getUuid() const noexcept override;
 
     bool checkDocumentCapabilities(Capabilities) const noexcept;
     bool checkDocumentOption(Options) const noexcept;
diff --git a/src/Lib/Document/VivyDocumentStore.cc b/src/Lib/Document/VivyDocumentStore.cc
index bdf6674dfa590094e5c260b29c22b231045db2c3..5e2ca6fb98915c88d3c89d10dd0eeee6c57649f0 100644
--- a/src/Lib/Document/VivyDocumentStore.cc
+++ b/src/Lib/Document/VivyDocumentStore.cc
@@ -5,37 +5,15 @@
 
 using namespace Vivy;
 
-std::shared_ptr<VivyDocument>
-VivyDocumentStore::loadDocument(const QString &file)
-{
-    QFileInfo fileinfo(file);
-    QString baseName = fileinfo.baseName();
-
-    if (VivyDocument *ret = new VivyDocument(file)) {
-        qDebug() << "Register document " << baseName << ret->getDocumentCapabilitiesString();
-        VivyDocument::Uuid uuid = ret->getUuid();
-        documents[uuid]         = std::shared_ptr<VivyDocument>(ret);
-        return documents[uuid];
-    } else {
-        qDebug() << "Failed to create document from " << file;
-        throw std::runtime_error("Failed to create the document");
-    }
-}
-
-bool
-VivyDocumentStore::isDocumentPresent(const VivyDocument::Uuid &uuid) noexcept
-{
-    return documents.count(uuid) >= 1;
-}
-
 std::shared_ptr<VivyDocument>
 VivyDocumentStore::newDocument(VivyDocument::Options opt)
 {
-    QString newDocName = newDocumentBaseName + QString::number(newDocumentNumber++);
+    const QString newDocName = newDocumentBaseName + QString::number(newDocumentNumber++);
+    auto ret                 = std::make_shared<VivyDocument>(newDocName, opt);
 
-    if (auto ret = std::make_shared<VivyDocument>(newDocName, opt)) {
-        VivyDocument::Uuid uuid = ret->getUuid();
-        documents[uuid]         = ret;
+    if (ret) {
+        const Uuid uuid = ret->getUuid();
+        documents[uuid] = ret;
         qDebug() << "Create new document " << newDocName << "with uuid" << uuid;
         return ret;
     } else {
@@ -43,20 +21,3 @@ VivyDocumentStore::newDocument(VivyDocument::Options opt)
         throw std::runtime_error("Failed to create the document");
     }
 }
-
-void
-VivyDocumentStore::closeDocument(const VivyDocument::Uuid &uuid) noexcept
-{
-    qDebug() << "Store is closing the document " << uuid;
-    documents.remove(uuid);
-}
-
-std::shared_ptr<VivyDocument>
-VivyDocumentStore::getDocument(const VivyDocument::Uuid &uuid) const
-{
-    if (!documents.contains(uuid)) {
-        qCritical() << "Couldn't find the document " << uuid;
-        throw std::runtime_error("Can't find the document");
-    }
-    return documents.value(uuid);
-}
diff --git a/src/Lib/Document/VivyDocumentStore.hh b/src/Lib/Document/VivyDocumentStore.hh
index f25fd3f7d374840596fa81ee0df07a38ddc4db66..c2ac6b8e729a8befca9c085aeac25af81141a42b 100644
--- a/src/Lib/Document/VivyDocumentStore.hh
+++ b/src/Lib/Document/VivyDocumentStore.hh
@@ -1,42 +1,23 @@
-#ifndef VIVY_DOCUMENTSTORE_H
-#define VIVY_DOCUMENTSTORE_H
+#pragma once
+
+#ifndef __cplusplus
+#error "This is a C++ header"
+#endif
 
 #include "VivyDocument.hh"
 #include "../Utils.hh"
-
-#include <QMap>
-#include <QString>
-#include <memory>
+#include "../CRTPStore.hh"
 
 namespace Vivy
 {
-class VivyDocumentStore final {
-    VIVY_UNMOVABLE_OBJECT(VivyDocumentStore)
+class VivyDocumentStore final : public CRTPStore<VivyDocumentStore, VivyDocument> {
+    VIVY_STORAGE_CLASS(VivyDocumentStore, VivyDocument)
 
 public:
     explicit VivyDocumentStore() noexcept = default;
-    ~VivyDocumentStore() noexcept         = default;
 
-    /* Create/load documents */
-    std::shared_ptr<VivyDocument> loadDocument(const QString &file);
+    // Create a new empty document with no backing file for the moment
     std::shared_ptr<VivyDocument> newDocument(VivyDocument::Options opt = VivyDocument::NoOption);
-
-    /* Get to see if a document is already present or not */
-    [[nodiscard("handle-it")]] bool isDocumentPresent(const VivyDocument::Uuid &) noexcept;
-
-    /* Close a document, please be sure to not used any of the dangling
-     * references to the closed document... */
-    void closeDocument(const VivyDocument::Uuid &uuid) noexcept;
-
-    /* Get stored documents */
-    std::shared_ptr<VivyDocument> getDocument(const VivyDocument::Uuid &uuid) const;
-
-private:
-    QMap<VivyDocument::Uuid, std::shared_ptr<VivyDocument>> documents;
-    uint newDocumentNumber{ 1 };
-    static inline const QString newDocumentBaseName = "Untitled ";
 };
 
 }
-
-#endif // VIVY_DOCUMENTSTORE_H
diff --git a/src/Lib/Script/ScriptDocument.cc b/src/Lib/Script/ScriptDocument.cc
new file mode 100644
index 0000000000000000000000000000000000000000..a74328f060f267012815b587bf335580eacc31eb
--- /dev/null
+++ b/src/Lib/Script/ScriptDocument.cc
@@ -0,0 +1,33 @@
+#include "ScriptDocument.hh"
+
+#include <QFileInfo>
+
+using namespace Vivy::Script;
+
+ScriptDocument::ScriptDocument(const QString &path)
+{
+    const QFileInfo file(path);
+    if (!file.exists())
+        throw std::runtime_error("File don't exists, don't create ScriptDocument");
+    name = file.absoluteFilePath();
+}
+
+bool
+ScriptDocument::rename(const QString &newName) noexcept
+{
+    /* Compute new paths */
+    const QFileInfo newPath(newName);
+    return renameWith(newPath, [=, this]() noexcept { name = newName; });
+}
+
+QString
+ScriptDocument::getName() const noexcept
+{
+    return name;
+}
+
+Vivy::Uuid
+ScriptDocument::getUuid() const noexcept
+{
+    return uuid;
+}
diff --git a/src/Lib/Script/ScriptDocument.hh b/src/Lib/Script/ScriptDocument.hh
new file mode 100644
index 0000000000000000000000000000000000000000..f5394514e48a5235d64c7c2e4c7f4c71c66c2ed6
--- /dev/null
+++ b/src/Lib/Script/ScriptDocument.hh
@@ -0,0 +1,24 @@
+#pragma once
+
+#ifndef __cplusplus
+#error "This is a C++ header"
+#endif
+
+#include "../AbstractDocument.hh"
+#include "../Uuid.hh"
+
+namespace Vivy::Script
+{
+class ScriptDocument final : public AbstractDocument {
+public:
+    explicit ScriptDocument(const QString &name);
+
+    bool rename(const QString &) noexcept override;
+    QString getName() const noexcept override;
+    Uuid getUuid() const noexcept override;
+
+private:
+    QString name{};
+    const Uuid uuid{};
+};
+}
diff --git a/src/Lib/Script/ScriptStore.cc b/src/Lib/Script/ScriptStore.cc
new file mode 100644
index 0000000000000000000000000000000000000000..deb8b89ec8427d0f5170498d48d2a5e01505889e
--- /dev/null
+++ b/src/Lib/Script/ScriptStore.cc
@@ -0,0 +1,4 @@
+#include "ScriptStore.hh"
+#include "../Uuid.hh"
+
+using namespace Vivy::Script;
diff --git a/src/Lib/Script/ScriptStore.hh b/src/Lib/Script/ScriptStore.hh
new file mode 100644
index 0000000000000000000000000000000000000000..8cddd1ebb2e84783d9e5926c479d8d17c9caea3b
--- /dev/null
+++ b/src/Lib/Script/ScriptStore.hh
@@ -0,0 +1,14 @@
+#pragma once
+
+#include "../CRTPStore.hh"
+#include "ScriptDocument.hh"
+
+namespace Vivy::Script
+{
+class ScriptStore final : public CRTPStore<ScriptStore, ScriptDocument> {
+    VIVY_STORAGE_CLASS(ScriptStore, ScriptDocument)
+
+public:
+    explicit ScriptStore() noexcept = default;
+};
+}
diff --git a/src/Lib/Uuid.hh b/src/Lib/Uuid.hh
new file mode 100644
index 0000000000000000000000000000000000000000..02e0801b19eecf10adc8144280aa61d1c98cc30d
--- /dev/null
+++ b/src/Lib/Uuid.hh
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <QUuid>
+
+namespace Vivy
+{
+class Uuid : public QUuid {
+public:
+    explicit Uuid()
+        : QUuid(QUuid::createUuid())
+    {
+    }
+
+    QString toString() const noexcept
+    {
+        return QUuid::toString(Uuid::WithoutBraces);
+    }
+};
+}
diff --git a/src/UI/AbstractDocumentView.hh b/src/UI/AbstractDocumentView.hh
index e73814ba43fd51bd424095a6378e1d57265dd027..43dc02e99877050426f3f9a227f4b57ce3e84692 100644
--- a/src/UI/AbstractDocumentView.hh
+++ b/src/UI/AbstractDocumentView.hh
@@ -5,7 +5,7 @@
 #endif
 
 #include "../Lib/Utils.hh"
-#include "../Lib/Document/AbstractDocument.hh"
+#include "../Lib/AbstractDocument.hh"
 #include <QMainWindow>
 #include <QDockWidget>
 #include <QAction>
@@ -27,7 +27,6 @@ public:
 
 public:
     explicit AbstractDocumentView(Type, QWidget *parent = nullptr) noexcept;
-    virtual ~AbstractDocumentView() noexcept = default;
 
     virtual void closeDocument() noexcept  = 0;
     virtual void openProperties() noexcept = 0;
diff --git a/src/UI/MainWindow.hh b/src/UI/MainWindow.hh
index 24f65893017c58c00b52f56077dbadbe87c7cfbd..0da5f538c52619e3fd2298b675c060315b316520 100644
--- a/src/UI/MainWindow.hh
+++ b/src/UI/MainWindow.hh
@@ -5,7 +5,7 @@
 #endif
 
 #include "../Lib/Utils.hh"
-#include "../Lib/Document/AbstractDocument.hh"
+#include "../Lib/AbstractDocument.hh"
 #include "../Lib/Document/VivyDocumentStore.hh"
 #include "DocumentViews/AudioVisualizer.hh"
 #include "VivyDocumentView.hh"