diff --git a/CMakeLists.txt b/CMakeLists.txt
index e1dfd60b8ff040ecaa0e3a29e6bf07d1517049fe..3feb433be94d72e58fd2f41f8a7b02ff1de0a10c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,49 +1,49 @@
 cmake_minimum_required(VERSION 3.17)
-
-# Alpha Vivy, CXX only
 project(Vivy VERSION 0.1 LANGUAGES CXX)
 cmake_policy(SET CMP0100 NEW) # Let cmake use moc and uic for .hh files
 cmake_policy(SET CMP0009 NEW) # Do not follow symlinks with GLOB_RECURSE
 
-if(CMAKE_BUILD_TYPE STREQUAL "Release")
-    set(CMAKE_BUILD_TYPE RelWithDebInfo)
+if(CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
+    set(CMAKE_BUILD_TYPE    RelWithDebInfo)
+    set(CARGO_RELEASE_BUILD "--release")
+else()
+    set(CMAKE_BUILD_TYPE Debug)
 endif()
 message(STATUS "The installation prefix is ${CMAKE_INSTALL_PREFIX}")
 message(STATUS "The build type is ${CMAKE_BUILD_TYPE}")
 
+set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Pass -fPIC
+set(CMAKE_COLOR_MAKEFILE            ON)
+set(CMAKE_COLOR_DIAGNOSTICS         ON)
+set(CMAKE_EXPORT_COMPILE_COMMANDS   ON) # Always to that...
+set(THREADS_PREFER_PTHREAD_FLAG     ON) # Pthread ftw
+set(CMAKE_AUTOUIC                   ON)
+set(CMAKE_AUTOMOC                   ON)
+set(CMAKE_AUTORCC                   ON)
+
+# Dependencies
+find_package(Qt6 COMPONENTS Widgets OpenGL OpenGLWidgets REQUIRED)
+find_library(AVCODEC_LIBRARY    avcodec    4.0 REQUIRED)
+find_library(AVUTIL_LIBRARY     avutil     4.0 REQUIRED)
+find_library(SWRESAMPLE_LIBRARY swresample     REQUIRED)
+find_library(AVFORMAT_LIBRARY   avformat       REQUIRED)
+find_library(MPV_LIBRARY        mpv            REQUIRED)
+
 # Don't forget for specific things
-if(WIN32)
-    message(STATUS "You are building on windows, pay attenion to the dependencies")
-endif()
 if(MSVC OR MSYS OR MINGW)
-    message(STATUS "You are building with a windows compiler")
+    set(Qt6_USE_STATIC_LIBS    ON)
+    set(Qt6_USE_STATIC_RUNTIME ON)
+    find_package(dlfcn-win32   REQUIRED)
+    add_compile_definitions(TERMIWIN_DONOTREDEFINE)
+    message(STATUS "You are cross-compiling for windows")
 elseif(APPLE)
     message(STATUS "You are building on MacOS X")
 elseif(UNIX AND NOT APPLE)
     message(STATUS "You are building on Linux, FreeBSD or any other toaster OS")
 else()
-    message(FATAL_ERROR "The OS is not recognized")
+    message(FATAL_ERROR "The OS is not recognized or not supported, if you are building on windows use a cross-compiler from a toaster OS")
 endif()
 
-set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Pass -fPIC
-set(CMAKE_COLOR_MAKEFILE            ON)
-set(CMAKE_COLOR_DIAGNOSTICS         ON)
-set(CMAKE_EXPORT_COMPILE_COMMANDS   ON)
-set(THREADS_PREFER_PTHREAD_FLAG     ON) # Pthread ftw
-
-# For Qt
-find_package(Qt6 COMPONENTS Widgets OpenGL OpenGLWidgets REQUIRED)
-set(CMAKE_AUTOUIC ON)
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-
-# Find others dependencies
-find_library(AVCODEC_LIBRARY    avcodec     4.0 REQUIRED)
-find_library(AVUTIL_LIBRARY     avutil      4.0 REQUIRED)
-find_library(SWRESAMPLE_LIBRARY swresample      REQUIRED)
-find_library(AVFORMAT_LIBRARY   avformat        REQUIRED)
-find_library(MPV_LIBRARY        mpv             REQUIRED)
-
 # Grab all files
 file(GLOB_RECURSE Vivy_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc")
 file(GLOB_RECURSE Vivy_INC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hh")
@@ -52,55 +52,45 @@ if(APPLE)
 endif()
 set(PROJECT_SOURCES ${Vivy_SRC} ${Vivy_INC} ${Vivy_APPLE_SRC})
 
+# The Rust lib
+add_custom_target(libvvs
+    COMMAND "${CMAKE_CURRENT_SOURCE_DIR}/utils/scripts/build-libvvs.bash"
+        "${CMAKE_CURRENT_BINARY_DIR}" ${CARGO_RELEASE_BUILD}
+    BYPRODUCTS  vvcc libvvs.a
+    COMMENT     "Rust library to embed into Vivy"
+    USES_TERMINAL
+)
+set_property(TARGET libvvs PROPERTY ADDITIONAL_CLEAN_FILES "vvcc;libvvs.a")
+install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/vvcc" DESTINATION bin)
+
 # Add the Vivy executable
 qt_add_executable(Vivy ${PROJECT_SOURCES} rsc/VivyRessources.qrc)
 qt_set_finalizer_mode(Vivy ENABLE MODES static_plugins)
+add_dependencies(Vivy libvvs)
+install(TARGETS Vivy RUNTIME DESTINATION bin)
 
-set(Vivy_PRECOMPILED_INC PRIVATE src/PreCompiledHeaders.hh)
-
-set_property(TARGET Vivy PROPERTY CXX_STANDARD 20)
+set_property(TARGET Vivy PROPERTY CXX_STANDARD      20)
 set_property(TARGET Vivy PROPERTY AUTOSTATICPLUGINS ON)
 
 # Link dependencies to Vivy
 target_link_libraries(Vivy PRIVATE Qt6::Widgets Qt::OpenGL Qt::OpenGLWidgets)
-target_link_libraries(Vivy PRIVATE ${AVCODEC_LIBRARY})
-target_link_libraries(Vivy PRIVATE ${AVUTIL_LIBRARY})
+target_link_libraries(Vivy PRIVATE ${AVCODEC_LIBRARY} ${AVUTIL_LIBRARY} ${AVFORMAT_LIBRARY})
 target_link_libraries(Vivy PRIVATE ${SWRESAMPLE_LIBRARY})
-target_link_libraries(Vivy PRIVATE ${AVFORMAT_LIBRARY})
 target_link_libraries(Vivy PRIVATE ${MPV_LIBRARY})
+target_link_libraries(Vivy PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/libvvs.a)
 
 # Headers related things
 target_include_directories(Vivy PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
-target_precompile_headers(Vivy PRIVATE ${Vivy_PRECOMPILED_INC})
-
-# Set Vivy's needed C++ features
-target_compile_features(Vivy PRIVATE
-    cxx_std_20
-    cxx_auto_type
-    cxx_deleted_functions
-    cxx_explicit_conversions
-    cxx_final
-    cxx_inline_namespaces
-    cxx_lambdas
-    cxx_noexcept
-    cxx_nonstatic_member_init
-    cxx_nullptr
-    cxx_override
-    cxx_range_for
-    cxx_strong_enums
-)
+target_precompile_headers(Vivy  PRIVATE src/PreCompiledHeaders.hh)
 
 # More options and warnings
 target_compile_options(Vivy PRIVATE
     -Wall -Wextra -Wpedantic
     -Wshadow
-    -Wcast-align
-    -Wconversion
-    -Wsign-conversion
+    -Wcast-align -Wconversion -Wsign-conversion -Wdouble-promotion
     -Wunused-variable
     -Wmisleading-indentation
     -Wnull-dereference
-    -Wdouble-promotion
     -Wformat=2
     -Woverloaded-virtual
     -Wnon-virtual-dtor
@@ -110,22 +100,18 @@ target_compile_options(Vivy PRIVATE
 # Prepare for Qt6
 target_compile_definitions(Vivy PRIVATE
     MPV_ENABLE_DEPRECATED=0
-    QT_DISABLE_DEPRECATED_BEFORE=0x050F00
     QT_NO_CAST_TO_ASCII
     QT_RESTRICTED_CAST_FROM_ASCII
     QTCREATOR_UTILS_STATIC_LIB
 )
 
 # Some compiler specific warnings and options
-if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
+if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
     target_compile_options(Vivy PRIVATE
         -Weverything
 
         # Disable some things because we want C++20 and don't control some Qt generated files...
-        -Wno-c++98-compat
-        -Wno-c++98-compat-pedantic
-        -Wno-c++98-c++11-c++14-c++17-compat-pedantic
-        -Wno-c++20-compat
+        -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-c++98-c++11-c++14-c++17-compat-pedantic -Wno-c++20-compat
 
         # Different versions of MPV...
         -Wno-switch-enum
@@ -137,7 +123,7 @@ if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
         -Wno-global-constructors
         -Wno-exit-time-destructors
     )
-elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
+elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
     target_compile_options(Vivy PRIVATE
         # Different versions of MPV...
         -Wno-switch
@@ -149,29 +135,21 @@ elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
 endif()
 
 set_target_properties(Vivy PROPERTIES
-    MACOSX_BUNDLE_GUI_IDENTIFIER kurisu.iiens.net
-    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
+    MACOSX_BUNDLE_GUI_IDENTIFIER       kurisu.iiens.net
+    MACOSX_BUNDLE_BUNDLE_VERSION       ${PROJECT_VERSION}
     MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
 )
 
-# Set ASAN
-if("x${CMAKE_BUILD_TYPE}" STREQUAL "xDebug")
-    if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
-        target_compile_options(Vivy PRIVATE -g -O1
-            -fsanitize=address
-            -fno-omit-frame-pointer
-            -fsanitize-address-use-after-return=always
-        )
-    elseif (${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
-        target_compile_options(Vivy PRIVATE -g -O1 -fsanitize=address -fno-omit-frame-pointer)
-    endif()
-
-    target_link_libraries(Vivy PRIVATE -g -O1 -fsanitize=address)
-endif()
-
-# Linking stuff
+# Linking stuff & ASAN on UNIX
 if(UNIX)
     target_link_options(Vivy PRIVATE -Wl,-rpath,. -rdynamic)
+    if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
+        set(Clang_CO -fsanitize=address -fno-omit-frame-pointer -fsanitize-address-use-after-return=always)
+        set(GNU_CO   -fsanitize=address -fno-omit-frame-pointer)
+        target_compile_options(Vivy PRIVATE ${${CMAKE_CXX_COMPILER_ID}_CO})
+        target_compile_options(Vivy PRIVATE -g -O1)
+        target_link_libraries( Vivy PRIVATE -g -O1 -fsanitize=address)
+    endif()
 elseif(WIN32)
     target_link_options(Vivy PRIVATE
         -static
diff --git a/README.md b/README.md
index a179e61ed95560827ceb8e0395535b37d9ccdcc7..9efaab231e39c45ab4c49c293612bde90beae24d 100644
--- a/README.md
+++ b/README.md
@@ -8,26 +8,23 @@
 - [mpv](https://mpv.io/) development library
 - [Qt6](https://www.qt.io/) development library: QtCore, QtWidgets, QtOpenGL, QtOpenGLWidgets.
 - The AV libraries: libavutil libavcodec libavformat
-- [cbindgen](https://github.com/mozilla/cbindgen): `cargo install --force cbindgen`
+- Some unix utils, the `jq` binary, the `bash` shell.
 
 ## Build
 
 Simply use cmake to build in another folder of the source folder:
-```
-cmake -Bbuild -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER=clang
+
+```bash
+cmake -Bbuild -DCMAKE_CXX_COMPILER=clang++ -CDMAKE_INSTALL_PREFIX=$HOME/.local -GNinja
+ninja -Cbuild
+ninja -Cbuild install
 ```
 
-To do a debug build, use the debug switch with cmake: `-DCMAKE_BUILD_TYPE=Debug`. Note that the last
-option is here to generate the `compile_commands.json`, you should copy it at the root of the
-project.
+To develop Vivy, you need to pass the following argument to cmake: `-DCMAKE_BUILD_TYPE=Debug`. Also,
+don't forget to copy the compile_commands.json file from the build folder into the project's root.
 
 ## Licence
 
-The C++ part of this software is licenced under the LGPL v3.0 or latter. The Rust part is under the
-MIT license.
-
----
-
-# TODO!
-
-- Use the rust things for the ASS instead of the C++ thing.
+- The C++ part of this software is licenced under [the LGPL v3.0 or latter](/LICENSE).
+- The Rust part is under the [MIT license](/src/Rust/LICENSE.txt)
+- The NotoSans fonts are distributed using the [OFL licence](/src/Rust/vvs_font/fonts/NotoSans-LICENCE-OFL.txt)
diff --git a/src/Lib/Ass/Ass.hh b/src/Lib/Ass/Ass.hh
deleted file mode 100644
index 051ea06210ba9691ee322f0035ae4d862353f5f6..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/Ass.hh
+++ /dev/null
@@ -1,11 +0,0 @@
-#ifndef VIVY_ASS_ASS_H
-#define VIVY_ASS_ASS_H
-
-#include "Lib/Ass/Line.hh"
-#include "Lib/Ass/Syl.hh"
-#include "Lib/Ass/Style.hh"
-#include "Lib/Ass/AssPrivate.hh"
-#include "Lib/Ass/AssFactory.hh"
-#include "Lib/Ass/StyleProperties.hh"
-
-#endif // VIVY_ASS_ASS_H
diff --git a/src/Lib/Ass/AssFactory.cc b/src/Lib/Ass/AssFactory.cc
deleted file mode 100644
index aa56e403dfbf6b46bd1296ecb45f4344e4998341..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/AssFactory.cc
+++ /dev/null
@@ -1,169 +0,0 @@
-#include "PreCompiledHeaders.hh"
-#include "Lib/Ass/AssFactory.hh"
-
-using namespace Vivy::Ass;
-
-bool
-AssFactory::initFromStorage() noexcept
-{
-    QTextStream in(&diskStorage);
-    QString currentSection{};
-    quint64 lineIndex = 0;
-    QStringList stylesContent{};
-    QStringList eventsContent{};
-
-    while (!in.atEnd()) {
-        const QString line = in.readLine().trimmed();
-
-        // Dectect comment
-        if (line.startsWith(";") || line.isEmpty()) {
-            lineIndex++;
-            continue;
-        }
-
-        // Dectect sections
-        else if (line.startsWith("[") && line.endsWith("]")) {
-            currentSection = line.mid(1, line.size() - 2);
-            logDebug() << "Parsing section " << VIVY_LOG_QUOTED(currentSection);
-            if (!validSections.contains(currentSection)) {
-                logWarning() << "The current section " << VIVY_LOG_QUOTED(currentSection)
-                             << " is invalid, ignoring it";
-                currentSection = "";
-            }
-        }
-
-        // Other lines
-        else if (!currentSection.isEmpty()) {
-            const int separatorIndex = line.indexOf(": ");
-            const int baseValueIndex = separatorIndex + 2;
-
-            // Easy way to see if the line was invalid
-            if (separatorIndex < 0)
-                logWarning() << "Invalid line #" << lineIndex << ": " << line;
-
-            // Script's info
-            else if (currentSection == sectionScriptInfo) {
-                assInfo.insert(line.mid(0, separatorIndex), line.mid(baseValueIndex));
-                logDebug() << "Got line #" << lineIndex << ": " << line;
-            }
-
-            // Skip the headers and the comment lines
-            else if ((currentSection == sectionStyles) && line.startsWith("Style: ")) {
-                stylesContent.append(line);
-            } else if ((currentSection == sectionEvents) && line.startsWith("Dialogue: ")) {
-                eventsContent.append(line);
-            } else if ((currentSection == sectionEvents) && line.startsWith("Comment: ")) {
-                eventsContent.append(line);
-            }
-        }
-
-        lineIndex++;
-    }
-
-    // Construct the styles and the lines
-    try {
-        for (const auto &styleLine : stylesContent)
-            assStyles.push_back(std::make_shared<Style>(styleLine));
-        for (const auto &assLine : eventsContent)
-            assLines.push_back(std::make_shared<Line>(this, assLine));
-    } catch (const std::runtime_error &e) {
-        logError() << "Failed to create ASS style or events with error: " << e.what();
-    }
-
-    logDebug() << "Got " << assLines.size() << " ASS dialog lines";
-
-    return true;
-}
-
-bool
-AssFactory::checkValidity() const noexcept
-{
-    if (assInfo.isEmpty()) {
-        logError() << "Empty info section";
-        return false;
-    }
-
-    // Check for fields that must be integers
-    SectionContent::const_iterator it        = assInfo.begin();
-    const SectionContent::const_iterator end = assInfo.end();
-    while (it != end) {
-        bool ok = false;
-        if (intTypeFields.contains(it.key()) && (static_cast<void>(it.value().toInt(&ok)), !ok)) {
-            logError() << it.key() << " is not an integer: " << it.value();
-            return false;
-        }
-        ++it;
-    }
-
-    // Check for fixed values fields
-    for (const auto &fixedValues : checkedValues) {
-        if (const auto &first = fixedValues.first;
-            assInfo.contains(first) && assInfo[first] != fixedValues.second) {
-            logError() << "Invalid " << first << " as it should be equal to " << fixedValues.second
-                       << " but was " << assInfo[first];
-            return false;
-        }
-    }
-
-    return true;
-}
-
-AssFactory::AssFactory(const QString &fileName)
-    : diskStorage(fileName)
-{
-    if (!diskStorage.open(QIODevice::ReadOnly | QIODevice::Text))
-        throw std::runtime_error("failed to open file for reading");
-
-    if (!initFromStorage())
-        throw std::runtime_error("failed to init ass factory from file");
-
-    if (!checkValidity())
-        throw std::runtime_error("the loaded ass is invalid");
-}
-
-void
-AssFactory::getStyles(QVector<StylePtr> &ret) const noexcept
-{
-    ret.clear();
-    for (const auto &style : assStyles)
-        ret.push_back(style);
-}
-
-void
-AssFactory::getLines(QVector<LinePtr> &ret) const noexcept
-{
-    ret.clear();
-    for (const auto &line : assLines)
-        ret.push_back(line);
-}
-
-AssFactory::SectionContent
-AssFactory::getInfoSection() const noexcept
-{
-    return assInfo;
-}
-
-StyleWeakPtr
-AssFactory::getStyle(const QString &name) const noexcept
-{
-    auto findByName = [&name](const StylePtr &style) noexcept -> bool {
-        return style->getElementName() == name;
-    };
-
-    auto styleIt = std::find_if(std::begin(assStyles), std::end(assStyles), findByName);
-    if (styleIt != std::end(assStyles))
-        return StyleWeakPtr(*styleIt);
-
-    // Will be unable to lock
-    return StyleWeakPtr(spareNullStylePtr);
-}
-
-bool
-AssFactory::hasStyle(const QString &name) const noexcept
-{
-    for (const auto &stylePtr : assStyles) {
-        if (stylePtr->getElementName() == name)
-            return true;
-    }
-    return false;
-}
diff --git a/src/Lib/Ass/AssFactory.hh b/src/Lib/Ass/AssFactory.hh
deleted file mode 100644
index d8f753f5d97665144c53294aa21c3d4d9943a63f..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/AssFactory.hh
+++ /dev/null
@@ -1,60 +0,0 @@
-#pragma once
-
-#include "VivyApplication.hh"
-#include "Lib/Log.hh"
-#include "Lib/Utils.hh"
-#include "Lib/Ass/Style.hh"
-#include "Lib/Ass/Line.hh"
-#include "Lib/Ass/AssPrivate.hh"
-
-// An ASS file is basically an INI file, but some keys are present multiple
-// times (V4+ Styles/Style, Events/Dialogue, Events/Comment).
-
-namespace Vivy::Ass
-{
-class AssFactory final {
-    VIVY_UNMOVABLE_OBJECT(AssFactory)
-    VIVY_APP_LOGGABLE_OBJECT(AssFactory, logger)
-
-public:
-    enum class Section { ScriptInfo = 1, Styles = 2, Events = 3 };
-
-    using SectionContent = QMap<QString, QVariant>;
-
-private:
-    QFile diskStorage;
-    SectionContent assInfo{};
-    QVector<LinePtr> assLines{};
-    QVector<StylePtr> assStyles{};
-
-    StylePtr spareNullStylePtr{ nullptr };
-
-    static inline const QString sectionScriptInfo = "Script Info";
-    static inline const QString sectionStyles     = "V4+ Styles";
-    static inline const QString sectionEvents     = "Events";
-    static inline const QStringList validSections = { sectionEvents, sectionScriptInfo,
-                                                      sectionStyles };
-
-    static inline const QStringList intTypeFields{ "PlayResX", "PlayResY", "WrapStyle" };
-    static inline const QVector<QPair<QString, QString>> checkedValues{
-        { "ScriptType", "v4.00+" },
-        { "WrapStyle", "0" },
-        // { "YCbCr Matrix", "TV.601" },
-        { "ScaledBorderAndShadow", "yes" }
-    };
-
-    bool initFromStorage() noexcept;
-    bool checkValidity() const noexcept;
-
-public:
-    explicit AssFactory(const QString &);
-    ~AssFactory() noexcept = default;
-
-    bool hasStyle(const QString &) const noexcept;
-    StyleWeakPtr getStyle(const QString &) const noexcept;
-
-    SectionContent getInfoSection() const noexcept;
-    void getStyles(QVector<StylePtr> &) const noexcept;
-    void getLines(QVector<LinePtr> &) const noexcept;
-};
-}
diff --git a/src/Lib/Ass/AssPrivate.hh b/src/Lib/Ass/AssPrivate.hh
deleted file mode 100644
index b25192cfe7b50b2ea8b584ff33fd0699db02fed3..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/AssPrivate.hh
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-#include "PreCompiledHeaders.hh"
-
-namespace Vivy::Ass
-{
-class Style;
-class Line;
-
-using StylePtr = std::shared_ptr<Style>;
-using LinePtr  = std::shared_ptr<Line>;
-
-using StyleWeakPtr = std::weak_ptr<Style>;
-using LineWeakPtr  = std::weak_ptr<Line>;
-}
diff --git a/src/Lib/Ass/Line.cc b/src/Lib/Ass/Line.cc
deleted file mode 100644
index 91f8601c2a21c697abf4b3eba71320c6092e8e89..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/Line.cc
+++ /dev/null
@@ -1,137 +0,0 @@
-#include "PreCompiledHeaders.hh"
-#include "Lib/Ass/Line.hh"
-#include "Lib/Ass/AssFactory.hh"
-
-using namespace Vivy::Ass;
-
-Line::Line(AssFactory *const factory, const QString &lineString)
-    : assFactory(factory)
-{
-    enum LineIndex : int {
-        Layer   = 0, // int
-        Start   = 1, // time
-        End     = 2, // time
-        Style   = 3, // text
-        Name    = 4, // text
-        MarginL = 5, // int
-        MarginR = 6, // int
-        MarginV = 7, // int
-        Effect  = 8, // text
-        Text    = 9, // text
-        PastLastCode
-
-        // NOTE: time is of the form: `h:mm:ss.cc`
-    };
-
-    const QString lineHeader = QStringLiteral("Dialogue: ");
-    isComment                = !lineString.startsWith(lineHeader);
-
-    const QString lineContent = lineString.mid(lineString.indexOf(": ") + 2 /* strlen ": " */);
-    QStringList contentList   = lineContent.split(",", Qt::KeepEmptyParts, Qt::CaseInsensitive);
-
-    if (contentList.size() < LineIndex::PastLastCode)
-        throw std::runtime_error(("invalid number of items " + QString::number(contentList.size()) +
-                                  " instead of something superiror or equal to " +
-                                  QString::number(PastLastCode) + " for line: " + lineContent)
-                                     .toStdString());
-
-    layer  = Utils::decodeLineToInteger(contentList[LineIndex::Layer], "Layer is not an integer");
-    effect = contentList[LineIndex::Effect];
-    nameOrActor = contentList[LineIndex::Name];
-    start       = Utils::Time::fromString(contentList[LineIndex::Start]).toUInt();
-    end         = Utils::Time::fromString(contentList[LineIndex::End]).toUInt();
-
-    styleProperties.marginL =
-        Utils::decodeLineToInteger(contentList[LineIndex::MarginL], "MarginL is not an integer");
-    styleProperties.marginR =
-        Utils::decodeLineToInteger(contentList[LineIndex::MarginR], "MarginR is not an integer");
-    styleProperties.marginV =
-        Utils::decodeLineToInteger(contentList[LineIndex::MarginV], "MarginV is not an integer");
-
-    const QString style = contentList[LineIndex::Style];
-    if (!assFactory->hasStyle(style))
-        throw std::runtime_error(("Invalid or not declared style name: " + style).toStdString());
-    lineStyle = assFactory->getStyle(style);
-
-    // Pop all but the text, it may contains `,` characters
-    for (int i = 0; i < LineIndex::Text; ++i)
-        contentList.removeFirst();
-    ___contentAsText = contentList.join("");
-    initSylFromString(___contentAsText);
-}
-
-void
-Line::initSylFromString(const QString &line) noexcept
-{
-    // Matches syllabes like: `{\toto}{\alpha&HFF}content`
-    QRegularExpression re("((?:{[^}]*})+[^{]*)");
-    if (!re.isValid())
-        logFatal() << "The regex " << VIVY_LOG_QUOTED(re.pattern().toStdString().c_str())
-                   << " is not valid...";
-
-    bool once = false;
-    try {
-        QRegularExpressionMatchIterator it = re.globalMatch(line);
-
-        while (it.hasNext()) {
-            QRegularExpressionMatch match = it.next();
-            content.append(Syl(this, match.captured(1)));
-            once |= true;
-        }
-    } catch (const std::runtime_error &e) {
-        qCritical() << "Failed to init syllabes with line: " << VIVY_LOG_QUOTED(line)
-                    << ". Error was: " << e.what() << ". Fallback to all line is one syllabe";
-        once = false;
-    }
-
-    if (!once) {
-        content.clear();
-        content.append(Syl(this, line, Syl::ConstructMode::Raw));
-    }
-}
-
-void
-Line::setStart(quint64 s) noexcept
-{
-    start = s;
-    if (s > end)
-        end = s;
-}
-
-void
-Line::setEnd(quint64 s) noexcept
-{
-    end = s;
-    if (start > s)
-        start = s;
-}
-
-quint64
-Line::getDuration() const noexcept
-{
-    return end - start;
-}
-
-StyleProperties
-Line::getStyleProperties() const noexcept
-{
-    return styleProperties;
-}
-
-StyleWeakPtr
-Line::getStyle() const noexcept
-{
-    return lineStyle;
-}
-
-const QVector<Syl> &
-Line::getContent() const noexcept
-{
-    return content;
-}
-
-bool
-Line::getIsComment() const noexcept
-{
-    return isComment;
-}
diff --git a/src/Lib/Ass/Line.hh b/src/Lib/Ass/Line.hh
deleted file mode 100644
index ba0c30e068639a81ba73c1648c4ea31a208cb9d6..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/Line.hh
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include "PreCompiledHeaders.hh"
-#include "VivyApplication.hh"
-#include "Lib/Log.hh"
-#include "Lib/Ass/Syl.hh"
-#include "Lib/Ass/StyleProperties.hh"
-#include "Lib/Ass/Style.hh"
-
-namespace Vivy::Ass
-{
-class AssFactory;
-
-class Line final {
-    VIVY_APP_LOGGABLE_OBJECT(Line, logger)
-
-    quint64 start{ 0 };
-    quint64 end{ 0 };
-    int layer{ 0 };
-    bool isComment{ true };
-
-    QVector<Syl> content{};
-    StyleProperties styleProperties{};
-    QString effect{};
-    QString nameOrActor{};
-    StyleWeakPtr lineStyle;
-
-    QString ___contentAsText;
-
-    AssFactory *assFactory;
-
-public:
-    explicit Line(AssFactory *const, const QString &);
-
-    void setStart(quint64 s) noexcept;
-    void setEnd(quint64 s) noexcept;
-    quint64 getDuration() const noexcept;
-    bool getIsComment() const noexcept;
-
-    StyleProperties getStyleProperties() const noexcept;
-    StyleWeakPtr getStyle() const noexcept;
-    const QVector<Syl> &getContent() const noexcept;
-
-private:
-    void initSylFromString(const QString &) noexcept;
-};
-}
diff --git a/src/Lib/Ass/Style.cc b/src/Lib/Ass/Style.cc
deleted file mode 100644
index 0a78af9537991cd7d4f8d123ea79b3034967bcc8..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/Style.cc
+++ /dev/null
@@ -1,198 +0,0 @@
-#include "PreCompiledHeaders.hh"
-#include "Lib/Ass/Style.hh"
-#include "Lib/Utils.hh"
-
-using namespace Vivy::Ass;
-
-Style::Style(const QString &styleString)
-{
-    // Some usefull defines only needed in that function
-
-    enum StyleIndex : int {
-        Name     = 0,
-        FontName = 1,
-        FontSize = 2,
-
-        ColorPrimary   = 3,
-        ColorSecondary = 4,
-        ColorOutline   = 5,
-        ColorBack      = 6,
-
-        Bold      = 7,
-        Italic    = 8,
-        Underline = 9,
-        StrikeOut = 10,
-
-        ScaleX  = 11,
-        ScaleY  = 12,
-        Spacing = 13,
-        Angle   = 14,
-
-        BorderStyle = 15,
-
-        Outline = 16,
-        Shadow  = 17,
-
-        Alignement = 18,
-        MarginL    = 19,
-        MarginR    = 20,
-        MarginV    = 21,
-
-        Encoding = 22,
-
-        PastLastCode
-    };
-
-    const QString lineHeader = QStringLiteral("Style: ");
-
-    // Check line header and content items number
-
-    if (!styleString.startsWith(lineHeader))
-        throw std::runtime_error(("invalid style line header: " + styleString).toStdString());
-
-    const QString lineContent = styleString.mid(styleString.indexOf(": ") + 2 /* strlen ": " */);
-    const QStringList content = lineContent.split(",", Qt::KeepEmptyParts, Qt::CaseInsensitive);
-
-    if (content.size() != StyleIndex::PastLastCode)
-        throw std::runtime_error(("invalid number of items " + QString::number(content.size()) +
-                                  " instead of " + QString::number(PastLastCode) +
-                                  " for line: " + lineContent)
-                                     .toStdString());
-
-    // Unpack data from the line
-
-    styleName = content[StyleIndex::Name];
-    fontName  = content[StyleIndex::FontName];
-    fontSize =
-        Utils::decodeLineToInteger(content[StyleIndex::FontSize], "FontSize is not an integer");
-
-    primaryColor   = Color::fromString(content[StyleIndex::ColorPrimary]);
-    secondaryColor = Color::fromString(content[StyleIndex::ColorSecondary]);
-    outlineColor   = Color::fromString(content[StyleIndex::ColorOutline]);
-    backColor      = Color::fromString(content[StyleIndex::ColorBack]);
-
-    bold   = Utils::decodeLineToBoolean(content[StyleIndex::Bold], "Bold is not a boolean");
-    italic = Utils::decodeLineToBoolean(content[StyleIndex::Italic], "Italic is not a boolean");
-    underline =
-        Utils::decodeLineToBoolean(content[StyleIndex::Underline], "Underline is not a boolean");
-    strikeOut =
-        Utils::decodeLineToBoolean(content[StyleIndex::StrikeOut], "StrikeOut is not a boolean");
-
-    scaleX  = Utils::decodeLineToFloating(content[StyleIndex::ScaleX], "ScaleX is not a floating");
-    scaleY  = Utils::decodeLineToFloating(content[StyleIndex::ScaleY], "ScaleY is not a floating");
-    spacing = Utils::decodeLineToFloating(content[StyleIndex::ScaleY], "Spacing is not a floating");
-    angle   = Utils::decodeLineToFloating(content[StyleIndex::Angle], "Angle is not a floating");
-    borderStyle = Utils::decodeLineToFloating(content[StyleIndex::BorderStyle],
-                                              "BorderStyle is not a floating");
-    outline =
-        Utils::decodeLineToFloating(content[StyleIndex::Outline], "Outline is not a floating");
-    shadow = Utils::decodeLineToFloating(content[StyleIndex::Shadow], "Shadow is not a floating");
-
-    alignment =
-        Utils::decodeLineToInteger(content[StyleIndex::Alignement], "Alignement is not an integer");
-    if (alignment < 1 || alignment > 9)
-        throw std::runtime_error(
-            ("invalid line content: Alignement must be between 1 and 9 included, it was " +
-             QString::number(alignment))
-                .toStdString());
-
-    marginL = Utils::decodeLineToInteger(content[StyleIndex::MarginL], "MarginL is not an integer");
-    marginR = Utils::decodeLineToInteger(content[StyleIndex::MarginR], "MarginR is not an integer");
-    marginV = Utils::decodeLineToInteger(content[StyleIndex::MarginV], "MarginV is not an integer");
-    encoding =
-        Utils::decodeLineToInteger(content[StyleIndex::Encoding], "Encoding is not an integer");
-
-    if (encoding != 1)
-        logWarning() << "Encoding is not '1' in the ASS Style";
-}
-
-QString
-Color::toString(const QColor &c) noexcept
-{
-    return "&H" + QString::number(c.blue(), 16).toUpper() +
-           QString::number(c.green(), 16).toUpper() + QString::number(c.red(), 16).toUpper();
-}
-
-QColor
-Color::fromString(const QString &colorString) noexcept
-{
-    // Ignore the '&H' at the begeing of the color if needed
-    int startIndex = 0;
-    if (colorString[startIndex] == '&')
-        startIndex++;
-    if (colorString[startIndex] == 'H' || colorString[startIndex] == 'h')
-        startIndex++;
-
-    // In some cases, the color can begin by a '#'
-    if (colorString[startIndex] == '#')
-        startIndex++;
-
-    // A valid string color is like 'AARRGGBB' for now (skipped 'aH')
-    if (colorString.size() - startIndex != 8)
-        return Color::defaultValue;
-
-    bool ok_alpha = false;
-    bool ok_red   = false;
-    bool ok_green = false;
-    bool ok_blue  = false;
-    int alpha     = colorString.mid(startIndex, 2).toInt(&ok_alpha, 16);
-    int red       = colorString.mid(startIndex + 2, 2).toInt(&ok_red, 16);
-    int green     = colorString.mid(startIndex + 4, 2).toInt(&ok_green, 16);
-    int blue      = colorString.mid(startIndex + 6, 2).toInt(&ok_blue, 16);
-
-    if (!(ok_alpha && ok_red && ok_green && ok_blue))
-        return Color::defaultValue;
-
-    return QColor(red, green, blue, alpha);
-}
-
-QString
-Style::getElementName() const noexcept
-{
-    return styleName;
-}
-
-QJsonDocument
-Style::getProperties() const noexcept
-{
-    QJsonDocument ret;
-
-    QJsonObject styleFont{
-        { "Font name", fontName }, { "Font size", fontSize },  { "Bold", bold },
-        { "Italic", italic },      { "Underline", underline }, { "Strike Out", strikeOut },
-    };
-
-    QJsonObject styleColors{
-        { "Primary", Color::toString(primaryColor) },
-        { "Secondary", Color::toString(secondaryColor) },
-        { "Outline", Color::toString(outlineColor) },
-        { "Back", Color::toString(backColor) },
-    };
-
-    QJsonObject styleFontProperties{
-        { "Scale X", static_cast<double>(scaleX) },
-        { "Scale Y", static_cast<double>(scaleY) },
-        { "Spacing", static_cast<double>(spacing) },
-        { "Angle", static_cast<double>(angle) },
-        { "Border Style", static_cast<double>(borderStyle) },
-        { "Outline", static_cast<double>(outline) },
-        { "Shadow", static_cast<double>(shadow) },
-    };
-
-    QJsonObject styleMargins{
-        { "Left", marginL },
-        { "Right", marginR },
-        { "Vertical", marginV },
-    };
-
-    QJsonObject object{ { "Name", styleName },
-                        { "Font", styleFont },
-                        { "Font properties", styleFontProperties },
-                        { "Colors", styleColors },
-                        { "Margin", styleMargins },
-                        { "Alignement", alignment },
-                        { "Encoding", encoding } };
-
-    ret.setObject(object);
-    return ret;
-}
diff --git a/src/Lib/Ass/Style.hh b/src/Lib/Ass/Style.hh
deleted file mode 100644
index 6712368c054861e3f03368a3f27c4002f7166da6..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/Style.hh
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-
-#include "PreCompiledHeaders.hh"
-#include "VivyApplication.hh"
-#include "Lib/Log.hh"
-#include "Lib/Ass/AssPrivate.hh"
-
-namespace Vivy::Ass
-{
-struct Color {
-    static QColor fromString(const QString &) noexcept;
-    static QString toString(const QColor &) noexcept;
-
-    static inline const QColor defaultValue = QColor(0, 0, 0, 0);
-
-private:
-    Color() = default;
-};
-
-class Style final {
-    VIVY_APP_LOGGABLE_OBJECT(Style, logger)
-
-    QString styleName;
-    QString fontName;
-    int fontSize{};
-
-    QColor primaryColor{ Color::defaultValue }, secondaryColor{ Color::defaultValue },
-        outlineColor{ Color::defaultValue }, backColor{ Color::defaultValue };
-
-    bool bold{ false }, italic{ false }, underline{ false }, strikeOut{ false };
-
-    float scaleX{ 0.0 }, scaleY{ 0.0 };
-    float spacing{ 0.0 }, angle{ 0.0 }, borderStyle{ 0.0 };
-    float outline{ 0.0 }, shadow{ 0.0 };
-
-    int alignment{ 2 };                           // Alignement is bottom center
-    int marginL{ 0 }, marginR{ 0 }, marginV{ 0 }; // No margin by default
-    int encoding{ 1 }; // Encoding is set to 1 in most ASS files by default (at least in Aegisub)
-
-public:
-    // Should grab and copy a user-changeable default style
-    explicit Style(const Style &) = default;
-    explicit Style(const QString &);
-
-    Style &operator=(const Style &) = delete;
-    ~Style() noexcept               = default;
-
-    QString getElementName() const noexcept;
-    QJsonDocument getProperties() const noexcept;
-};
-}
diff --git a/src/Lib/Ass/StyleProperties.hh b/src/Lib/Ass/StyleProperties.hh
deleted file mode 100644
index eb7c04cdeaa10b215ef46a95a80ebe119ebcf5f0..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/StyleProperties.hh
+++ /dev/null
@@ -1,32 +0,0 @@
-#pragma once
-
-#include "PreCompiledHeaders.hh"
-#include "Lib/Ass/Style.hh"
-
-namespace Vivy::Ass
-{
-// Overrides some properties of the Style of an Ass::Line, Ass::Char, Ass::Syl
-
-struct StyleProperties final {
-    // Colors
-    QColor primaryColor{ Color::defaultValue }, secondaryColor{ Color::defaultValue },
-        outlineColor{ Color::defaultValue }, backColor{ Color::defaultValue };
-
-    QString fontName{}; // Can override the font's name
-    int fontSize{};     // The font size != the font scaling
-
-    bool bold{ false }, italic{ false }, underline{ false }, strikeOut{ false };
-
-    // Usefull for rotations
-    float angle{ 0.0 };
-
-    // No margin by default
-    int marginL{ 0 }, marginR{ 0 }, marginV{ 0 };
-
-    float scaleX{ 0.0 }, scaleY{ 0.0 };  // Font scaling
-    float outline{ 0.0 }, shadow{ 0.0 }; // Outline sizes
-
-    // Alignement is bottom center
-    int alignment{ 2 };
-};
-}
diff --git a/src/Lib/Ass/Syl.cc b/src/Lib/Ass/Syl.cc
deleted file mode 100644
index 20dc0ce44154185c31113789a598a9eb042da43c..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/Syl.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-#include "PreCompiledHeaders.hh"
-#include "Lib/Ass/Syl.hh"
-#include "Lib/Ass/Line.hh"
-
-using namespace Vivy::Ass;
-
-Syl::Syl(Line *const line, const QString &lineString, ConstructMode mode) noexcept
-    : content(lineString)
-    , styleProperties(line->getStyleProperties())
-    , duration(line->getDuration())
-    , parentLine(line)
-{
-    // Will override the `content`, but will be heavy anyway
-    if (mode == ConstructMode::ReadAssTags) {
-        const int textBegin = lineString.lastIndexOf('}') + 1;
-        content             = (textBegin >= lineString.size()) ? "" : lineString.mid(textBegin);
-        duration            = getDurationFromString(lineString);
-    }
-}
-
-quint64
-Syl::getDurationFromString(const QString &line) noexcept
-{
-    QRegularExpression re("\\\\(?:k|K|ko|kf)(\\d+)");
-    quint64 duration                   = 0;
-    QRegularExpressionMatchIterator it = re.globalMatch(line);
-
-    while (it.hasNext())
-        duration += it.next().captured(1).toUInt();
-
-    return duration;
-}
-
-QString
-Syl::getContent() const noexcept
-{
-    return content;
-}
diff --git a/src/Lib/Ass/Syl.hh b/src/Lib/Ass/Syl.hh
deleted file mode 100644
index 75da543cbf9ca1e9c188ff6a433b71b53b15ad4b..0000000000000000000000000000000000000000
--- a/src/Lib/Ass/Syl.hh
+++ /dev/null
@@ -1,33 +0,0 @@
-#pragma once
-
-#include "PreCompiledHeaders.hh"
-#include "Lib/Ass/StyleProperties.hh"
-
-namespace Vivy::Ass
-{
-class Line;
-
-class Syl final {
-private:
-    QString content;
-    StyleProperties styleProperties;
-    quint64 duration{ 0 };
-
-public:
-    Line *parentLine;
-
-public:
-    enum class ConstructMode {
-        Raw,        // Don't read ASS tags
-        ReadAssTags // Read ass tags
-    };
-
-    explicit Syl(Line *const, const QString &,
-                 ConstructMode mode = ConstructMode::ReadAssTags) noexcept;
-
-    QString getContent() const noexcept;
-
-private:
-    static quint64 getDurationFromString(const QString &) noexcept;
-};
-}
diff --git a/src/Lib/Document/CRTPSubDocument.hh b/src/Lib/Document/CRTPSubDocument.hh
index 3a3cf80b42b9878b34516df7e8e1137f3c6bc0da..22d9bf9b0ee67fed96692593126ca77260ba593c 100644
--- a/src/Lib/Document/CRTPSubDocument.hh
+++ b/src/Lib/Document/CRTPSubDocument.hh
@@ -10,7 +10,7 @@
 #include "Lib/Utils.hh"
 #include "Lib/Audio.hh"
 #include "Lib/Video.hh"
-#include "Lib/Ass/Ass.hh"
+#include "Rust/VVLib.hh"
 
 #define VIVY_ENABLE_IF_TYPE(Type) \
     template <typename = typename std::enable_if<!std::is_same<Type, void>::value>>
@@ -135,14 +135,17 @@ class AssSubDocument final : public CRTPSubDocument<AssDocumentType, AssSubDocum
     friend CRTPSubDocument<AssDocumentType, AssSubDocument, void>;
 
 public:
-    QString getElementName() const noexcept;
+    ~AssSubDocument() noexcept;
+
+    QString getElementName() const noexcept { return "AssSubDocument"; }
     QJsonDocument getProperties() const noexcept;
 
-    const QVector<Ass::LinePtr> &getLines() const noexcept;
-    const QVector<Ass::StylePtr> &getStyles() const noexcept;
+    const QVector<VVLib::ASSLine *> &getLines() const noexcept { return lines; }
+    const QVector<VVLib::ASSStyle *> &getStyles() const noexcept { return styles; }
 
 private:
-    QVector<Ass::StylePtr> styles;
-    QVector<Ass::LinePtr> lines;
+    VVLib::ASSContainer *ass_container{ nullptr };
+    QVector<VVLib::ASSStyle *> styles;
+    QVector<VVLib::ASSLine *> lines;
 };
 }
diff --git a/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc b/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc
index 96fc6dbea03b14b0b69285ea007bb3a4a1a78db4..ccd73b2a350cc1efecc3977d32a5aa992f3688e1 100644
--- a/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc
+++ b/src/Lib/Document/CRTPSubDocument/AssSubDocument.cc
@@ -1,5 +1,5 @@
 #include "PreCompiledHeaders.hh"
-#include "Lib/Document//CRTPSubDocument.hh"
+#include "Lib/Document/CRTPSubDocument.hh"
 #include "Lib/JsonBuilder.hh"
 
 using namespace Vivy;
@@ -8,35 +8,26 @@ using namespace Vivy;
 void
 AssSubDocument::initFromPath(const QString &path)
 {
-    Ass::AssFactory factory(path);
-    factory.getStyles(styles);
-    factory.getLines(lines);
-}
-
-QString
-AssSubDocument::getElementName() const noexcept
-{
-    return "AssSubDocument";
-}
-
-const QVector<Ass::LinePtr> &
-AssSubDocument::getLines() const noexcept
-{
-    return lines;
+    this->ass_container = VVLib::ASSContainerFromFile(path.toUtf8().data());
+    for (size_t i = 0; i < VVLib::ASSContainerGetLinesCount(this->ass_container); i += 1) {
+        this->lines.push_back(VVLib::ASSContainerGetLineAt(this->ass_container, i));
+    }
+    for (size_t i = 0; i < VVLib::ASSContainerGetStylesCount(this->ass_container); i += 1) {
+        this->styles.push_back(VVLib::ASSContainerGetStyleAt(this->ass_container, i));
+    }
 }
 
-const QVector<Ass::StylePtr> &
-AssSubDocument::getStyles() const noexcept
-{
-    return styles;
-}
+AssSubDocument::~AssSubDocument() noexcept { VVLib::ASSContainerDrop(this->ass_container); }
 
 QJsonDocument
 AssSubDocument::getProperties() const noexcept
 {
     QJsonObject styleObject;
-    for (const Ass::StylePtr &style : styles) {
-        styleObject.insert(style->getElementName(), style->getProperties().object());
+    for (size_t i = 0; i < VVLib::ASSContainerGetStylesCount(this->ass_container); i += 1) {
+        const auto view =
+            VVLib::ASSStyleGetName(VVLib::ASSContainerGetStyleAt(this->ass_container, i));
+        styleObject.insert(QString::number(i),
+                           QString::fromUtf8(view.str, static_cast<qsizetype>(view.len)));
     }
 
     return JsonBuilder::createOrderedJsonDocument({
diff --git a/src/Rust/Cargo.lock b/src/Rust/Cargo.lock
index 438b9cce5e2c3acb9b7aecd42b68361435637657..55a9cd7a64a9379ee95029ebd0118e7a92c0c751 100644
--- a/src/Rust/Cargo.lock
+++ b/src/Rust/Cargo.lock
@@ -57,6 +57,29 @@ version = "1.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
 
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
 [[package]]
 name = "bitflags"
 version = "2.4.1"
@@ -69,12 +92,46 @@ version = "0.6.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
 
+[[package]]
+name = "cbindgen"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49"
+dependencies = [
+ "clap 3.2.25",
+ "heck",
+ "indexmap 1.9.3",
+ "log",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "syn 1.0.109",
+ "tempfile",
+ "toml 0.5.11",
+]
+
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
+[[package]]
+name = "clap"
+version = "3.2.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
+dependencies = [
+ "atty",
+ "bitflags 1.3.2",
+ "clap_lex 0.2.4",
+ "indexmap 1.9.3",
+ "strsim",
+ "termcolor",
+ "textwrap",
+]
+
 [[package]]
 name = "clap"
 version = "4.4.7"
@@ -92,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
 dependencies = [
  "anstyle",
- "clap_lex",
+ "clap_lex 0.6.0",
  "strsim",
  "terminal_size",
 ]
@@ -103,7 +160,7 @@ version = "4.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bffe91f06a11b4b9420f62103854e90867812cd5d01557f853c5ee8e791b12ae"
 dependencies = [
- "clap",
+ "clap 4.4.7",
 ]
 
 [[package]]
@@ -115,7 +172,16 @@ dependencies = [
  "heck",
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.38",
+]
+
+[[package]]
+name = "clap_lex"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
+dependencies = [
+ "os_str_bytes",
 ]
 
 [[package]]
@@ -130,7 +196,7 @@ version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d3be86020147691e1d2ef58f75346a3d4d94807bfc473e377d52f09f0f7d77f7"
 dependencies = [
- "clap",
+ "clap 4.4.7",
  "roff",
 ]
 
@@ -150,6 +216,18 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "fastrand"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+
+[[package]]
+name = "hashbrown"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
 [[package]]
 name = "hashbrown"
 version = "0.14.2"
@@ -166,6 +244,25 @@ version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "indexmap"
+version = "1.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
+dependencies = [
+ "autocfg",
+ "hashbrown 0.12.3",
+]
+
 [[package]]
 name = "indexmap"
 version = "2.0.2"
@@ -173,9 +270,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
 dependencies = [
  "equivalent",
- "hashbrown",
+ "hashbrown 0.14.2",
 ]
 
+[[package]]
+name = "itoa"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+
 [[package]]
 name = "libc"
 version = "0.2.149"
@@ -233,6 +336,12 @@ version = "1.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
 
+[[package]]
+name = "os_str_bytes"
+version = "6.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1"
+
 [[package]]
 name = "owned_ttf_parser"
 version = "0.19.0"
@@ -260,6 +369,15 @@ dependencies = [
  "proc-macro2",
 ]
 
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
 [[package]]
 name = "regex"
 version = "1.10.2"
@@ -301,13 +419,19 @@ version = "0.38.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
 dependencies = [
- "bitflags",
+ "bitflags 2.4.1",
  "errno",
  "libc",
  "linux-raw-sys",
  "windows-sys",
 ]
 
+[[package]]
+name = "ryu"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+
 [[package]]
 name = "serde"
 version = "1.0.190"
@@ -325,7 +449,18 @@ checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.38",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.108"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
 ]
 
 [[package]]
@@ -343,6 +478,17 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
 [[package]]
 name = "syn"
 version = "2.0.38"
@@ -354,6 +500,28 @@ dependencies = [
  "unicode-ident",
 ]
 
+[[package]]
+name = "tempfile"
+version = "3.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "redox_syscall",
+ "rustix",
+ "windows-sys",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6093bad37da69aab9d123a8091e4be0aa4a03e4d601ec641c327398315f62b64"
+dependencies = [
+ "winapi-util",
+]
+
 [[package]]
 name = "terminal_size"
 version = "0.3.0"
@@ -364,6 +532,12 @@ dependencies = [
  "windows-sys",
 ]
 
+[[package]]
+name = "textwrap"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
+
 [[package]]
 name = "thiserror"
 version = "1.0.50"
@@ -381,7 +555,16 @@ checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.38",
+]
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
 ]
 
 [[package]]
@@ -411,7 +594,7 @@ version = "0.20.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "782bf6c2ddf761c1e7855405e8975472acf76f7f36d0d4328bd3b7a2fae12a85"
 dependencies = [
- "indexmap",
+ "indexmap 2.0.2",
  "serde",
  "serde_spanned",
  "toml_datetime",
@@ -461,13 +644,13 @@ name = "vvs_cli"
 version = "0.5.0"
 dependencies = [
  "anyhow",
- "clap",
+ "clap 4.4.7",
  "clap_complete",
  "clap_mangen",
  "log",
  "serde",
  "thiserror",
- "toml",
+ "toml 0.8.5",
  "vvs_font",
  "vvs_utils",
 ]
@@ -487,7 +670,7 @@ name = "vvs_lang"
 version = "0.5.0"
 dependencies = [
  "anyhow",
- "hashbrown",
+ "hashbrown 0.14.2",
  "log",
  "nom",
  "nom_locate",
@@ -497,13 +680,22 @@ dependencies = [
  "vvs_utils",
 ]
 
+[[package]]
+name = "vvs_lib"
+version = "0.5.0"
+dependencies = [
+ "cbindgen",
+ "log",
+ "vvs_ass",
+]
+
 [[package]]
 name = "vvs_procmacro"
 version = "0.5.0"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.38",
 ]
 
 [[package]]
@@ -515,6 +707,37 @@ dependencies = [
  "thiserror",
 ]
 
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
 [[package]]
 name = "windows-sys"
 version = "0.48.0"
@@ -607,5 +830,5 @@ checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn",
+ "syn 2.0.38",
 ]
diff --git a/src/Rust/Cargo.toml b/src/Rust/Cargo.toml
index aeba7e5ad0f4da0a66977cef64410c516894ec9d..7cfb804b33b601230a3e7fb2a18848960ffbe9de 100644
--- a/src/Rust/Cargo.toml
+++ b/src/Rust/Cargo.toml
@@ -1,13 +1,6 @@
 [workspace]
 resolver = "2"
-members = [
-    "vvs_cli",
-    "vvs_ass",
-    "vvs_font",
-    "vvs_lang",
-    "vvs_utils",
-    "vvs_procmacro",
-]
+members = ["vvs_*"]
 
 [workspace.package]
 version = "0.5.0"
@@ -20,11 +13,11 @@ license = "MIT"
 # Utils
 thiserror = "1"
 anyhow = "1"
-paste = "1"
 log = "0.4"
 bitflags = { version = "2", default-features = false }
 unicode-segmentation = "1"
 hashbrown = "0.14"
+cbindgen = "0.26"
 
 # Parsing
 regex = { version = "1", default-features = false, features = ["std"] }
diff --git a/src/Rust/VVLib.hh b/src/Rust/VVLib.hh
new file mode 100644
index 0000000000000000000000000000000000000000..a3e8f3b729c42914ffd4edee86de3d13ec0b7581
--- /dev/null
+++ b/src/Rust/VVLib.hh
@@ -0,0 +1,82 @@
+/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
+
+#pragma once
+
+/* Generated with cbindgen:0.26.0 */
+
+namespace VVLib {
+
+struct ASSContainer;
+
+struct ASSLine;
+
+/// Type used to describe an ASS style.
+struct ASSStyle;
+
+struct ASSSyllabe;
+
+/// Represents a string slice, the user may not modify this slice, never! Note that the string is
+/// not null terminated and may contains null bytes in it, use the len attribute to get the length
+/// of this string and convert it to your linking.
+struct StringSlice
+{
+    uintptr_t len;
+    const char *str;
+};
+
+extern "C" {
+
+/// Get the name of the style.
+///
+/// # Safety
+/// It is up to the user to ensure that the style is not dropped before the returned pointer.
+StringSlice ASSStyleGetName(const ASSStyle *this_);
+
+/// Get the number of lines in the container.
+uintptr_t ASSContainerGetLinesCount(const ASSContainer *this_);
+
+/// Get the number of syllabes in the line.
+uintptr_t ASSLineGetSyllabesCount(const ASSLine *this_);
+
+/// # Safety
+/// It is up to the user to ensure that no aliasing is done or that the line is not removed
+/// from the container before the pointer is dropped, or that the container is not dropped...
+ASSLine *ASSContainerGetLineAt(ASSContainer *this_, uintptr_t idx);
+
+/// # Safety
+/// It is up to the user to ensure that no aliasing is done or that the syllabe is not removed
+/// from the line before the pointer is dropped, or that the line is not removed from the
+/// container...
+ASSSyllabe *ASSLineGetSyllabeAt(ASSLine *this_, uintptr_t idx);
+
+/// Tells whever a line is commented or not.
+bool ASSLineIsCommented(const ASSLine *this_);
+
+/// Gets the style of the line, or 'Default' if it was not found/specified.
+StringSlice ASSLineGetStyle(const ASSLine *this_);
+
+/// # Safety
+/// The returned pointer must be freed
+StringSlice ASSSyllabeGetContent(const ASSSyllabe *this_);
+
+/// Load the ASS from a file, returns nullptr if an error was encountred.
+ASSContainer *ASSContainerFromFile(char *path);
+
+ASSStyle *ASSContainerGetStyleByName(ASSContainer *this_, const char *name);
+
+ASSStyle *ASSContainerGetStyleAt(ASSContainer *this_, uintptr_t idx);
+
+uintptr_t ASSContainerGetStylesCount(ASSContainer *this_);
+
+void ASSLineSetStartTime(ASSLine *this_, int64_t time);
+
+void ASSLineSetFiniTime(ASSLine *this_, int64_t time);
+
+/// Drop the container. It is file to pass a null pointer to this function.
+/// # Safety
+/// The use must ensure that no dangling references remains...
+void ASSContainerDrop(ASSContainer *this_);
+
+} // extern "C"
+
+} // namespace VVLib
diff --git a/src/Rust/vvs_ass/src/elements/line.rs b/src/Rust/vvs_ass/src/elements/line.rs
index 63df87f09256b591a6ed13421f264e77b0585aff..c62d983ba7753438b81f92a2b5b602b2d07911d6 100644
--- a/src/Rust/vvs_ass/src/elements/line.rs
+++ b/src/Rust/vvs_ass/src/elements/line.rs
@@ -2,11 +2,12 @@ use crate::{ASSAuxTable, ASSPosition, ASSSyllabePtr};
 
 #[derive(Debug, Default, Clone, PartialEq)]
 pub struct ASSLine {
+    pub is_comment: bool,
+    pub start: i64,
+    pub fini: i64,
     pub position: ASSPosition,
     pub content: Vec<ASSSyllabePtr>,
     pub aux: ASSAuxTable,
-    pub start: i64,
-    pub fini: i64,
 }
 
 #[derive(Debug, Default, Clone)]
@@ -43,6 +44,10 @@ impl From<ASSLine> for ASSLinePtr {
 }
 
 impl ASSLines {
+    pub fn get(&self, idx: usize) -> Option<ASSLinePtr> {
+        self.0.get(idx).cloned()
+    }
+
     pub fn len(&self) -> usize {
         self.0.len()
     }
diff --git a/src/Rust/vvs_ass/src/elements/syllabe.rs b/src/Rust/vvs_ass/src/elements/syllabe.rs
index 4c098045cfe2de182e5e9b54e8c20922cec6435e..6f66cdebefb24268dab775cc9b9db706f3116b90 100644
--- a/src/Rust/vvs_ass/src/elements/syllabe.rs
+++ b/src/Rust/vvs_ass/src/elements/syllabe.rs
@@ -43,6 +43,10 @@ impl From<ASSSyllabe> for ASSSyllabePtr {
 }
 
 impl ASSSyllabes {
+    pub fn get(&self, idx: usize) -> Option<ASSSyllabePtr> {
+        self.0.get(idx).cloned()
+    }
+
     pub fn len(&self) -> usize {
         self.0.len()
     }
diff --git a/src/Rust/vvs_ass/src/lib.rs b/src/Rust/vvs_ass/src/lib.rs
index 59575219123c8918200d5218621b456152507680..6dd7470fbd2ba75ce5a530dcda46709ca647e242 100644
--- a/src/Rust/vvs_ass/src/lib.rs
+++ b/src/Rust/vvs_ass/src/lib.rs
@@ -1,4 +1,5 @@
 //! ASS objects for Vivy.
+
 #![forbid(unsafe_code)]
 
 mod colors;
diff --git a/src/Rust/vvs_ass/src/styles.rs b/src/Rust/vvs_ass/src/styles.rs
index 81252927a34c624b9c392c61bd352438f1d9073b..c80e382b9adbf128c403caf5bd6281f0db612cc9 100644
--- a/src/Rust/vvs_ass/src/styles.rs
+++ b/src/Rust/vvs_ass/src/styles.rs
@@ -1,6 +1,9 @@
 use crate::{ASSAlign, ASSColor};
 
+/// cbindgen:derive-eq
+/// cbindgen:prefix-with-name
 #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
+#[repr(C)]
 pub enum ASSBorderStyle {
     #[default]
     OutlineAndDropShadow = 1,
diff --git a/src/Rust/vvs_lib/Cargo.toml b/src/Rust/vvs_lib/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..77b27a26befd71c76263c68dc3dcc623bf3b5c42
--- /dev/null
+++ b/src/Rust/vvs_lib/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "vvs_lib"
+version.workspace = true
+authors.workspace = true
+edition.workspace = true
+license.workspace = true
+description = "A C library to expose functionalities to C/C++"
+
+[lib]
+name = "vvs"
+crate-type = ["staticlib"]
+
+[dependencies]
+log.workspace = true
+
+vvs_ass = { path = "../vvs_ass" }
+
+[build-dependencies]
+cbindgen.workspace = true
diff --git a/src/Rust/vvs_lib/build.rs b/src/Rust/vvs_lib/build.rs
new file mode 100644
index 0000000000000000000000000000000000000000..e5c1757049178e066234d76fa0a3e2c119a5f1fd
--- /dev/null
+++ b/src/Rust/vvs_lib/build.rs
@@ -0,0 +1,23 @@
+use cbindgen::{Braces, Language, Style};
+
+fn main() {
+    cbindgen::Builder::new()
+        .with_crate(std::env::var("CARGO_MANIFEST_DIR").unwrap())
+        .with_parse_deps(true)
+        .with_parse_include(&["vvs_ass"])
+        .with_documentation(true)
+        .with_header("/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */")
+        .with_language(Language::Cxx)
+        .with_no_includes()
+        .with_include_version(true)
+        .with_line_length(120)
+        .with_style(Style::Both)
+        .with_cpp_compat(true)
+        .with_pragma_once(true)
+        .with_namespace("VVLib")
+        .with_tab_width(4)
+        .with_braces(Braces::NextLine)
+        .generate()
+        .expect("Failed to generate config")
+        .write_to_file("../VVLib.hh");
+}
diff --git a/src/Rust/vvs_lib/src/ass.rs b/src/Rust/vvs_lib/src/ass.rs
new file mode 100644
index 0000000000000000000000000000000000000000..6fb01408756cdc6c29960db1b01a14b092a07909
--- /dev/null
+++ b/src/Rust/vvs_lib/src/ass.rs
@@ -0,0 +1,166 @@
+use std::{
+    ffi::{c_char, CStr},
+    ptr::NonNull,
+};
+use vvs_ass::{ass_container_from_file, ASSContainer, ASSLine, ASSStyle, ASSSyllabe};
+
+/// Represents a string slice, the user may not modify this slice, never! Note that the string is
+/// not null terminated and may contains null bytes in it, use the len attribute to get the length
+/// of this string and convert it to your linking.
+#[repr(C)]
+pub struct StringSlice {
+    len: usize,
+    str: *const c_char,
+}
+
+impl<S: AsRef<str>> From<S> for StringSlice {
+    fn from(value: S) -> Self {
+        let value = value.as_ref();
+        StringSlice { len: value.len(), str: value.as_ptr() as *const _ }
+    }
+}
+
+/// Contains wrappers for the styles.
+pub mod style {
+    use super::*;
+
+    /// Get the name of the style.
+    ///
+    /// # Safety
+    /// It is up to the user to ensure that the style is not dropped before the returned pointer.
+    #[no_mangle]
+    pub extern "C" fn ASSStyleGetName(this: &ASSStyle) -> StringSlice {
+        StringSlice::from(&this.name)
+    }
+}
+
+/// Contains wrappers for the container, the line, syllabes, etc...
+pub mod elements {
+    use super::*;
+
+    /// Get the number of lines in the container.
+    #[no_mangle]
+    pub extern "C" fn ASSContainerGetLinesCount(this: &ASSContainer) -> usize {
+        this.lines.len()
+    }
+
+    /// Get the number of syllabes in the line.
+    #[no_mangle]
+    pub extern "C" fn ASSLineGetSyllabesCount(this: &ASSLine) -> usize {
+        this.content.len()
+    }
+
+    /// # Safety
+    /// It is up to the user to ensure that no aliasing is done or that the line is not removed
+    /// from the container before the pointer is dropped, or that the container is not dropped...
+    #[no_mangle]
+    pub unsafe extern "C" fn ASSContainerGetLineAt(this: &mut ASSContainer, idx: usize) -> *mut ASSLine {
+        match this.lines.get(idx) {
+            Some(line) => match line.0.write() {
+                Ok(mut line) => (&mut *line) as *mut _,
+                Err(err) => {
+                    log::error!("failed to get line n°{idx}: {err}");
+                    std::ptr::null_mut()
+                }
+            },
+            None => {
+                log::error!("failed to get line n°{idx}");
+                std::ptr::null_mut()
+            }
+        }
+    }
+
+    /// # Safety
+    /// It is up to the user to ensure that no aliasing is done or that the syllabe is not removed
+    /// from the line before the pointer is dropped, or that the line is not removed from the
+    /// container...
+    #[no_mangle]
+    pub unsafe extern "C" fn ASSLineGetSyllabeAt(this: &mut ASSLine, idx: usize) -> *mut ASSSyllabe {
+        match this.content.get(idx) {
+            Some(s) => match s.0.write() {
+                Ok(mut s) => (&mut *s) as *mut _,
+                Err(err) => {
+                    log::error!("failed to get syllabe n°{idx}: {err}");
+                    std::ptr::null_mut()
+                }
+            },
+            None => {
+                log::error!("failed to get syllabe n°{idx}");
+                std::ptr::null_mut()
+            }
+        }
+    }
+
+    /// Tells whever a line is commented or not.
+    #[no_mangle]
+    pub extern "C" fn ASSLineIsCommented(this: &ASSLine) -> bool {
+        this.is_comment
+    }
+
+    /// Gets the style of the line, or 'Default' if it was not found/specified.
+    #[no_mangle]
+    pub extern "C" fn ASSLineGetStyle(this: &ASSLine) -> StringSlice {
+        this.aux
+            .get("style")
+            .map(|style| match style {
+                vvs_ass::ASSAuxValue::String(str) => StringSlice::from(str),
+                _ => StringSlice::from("Default"),
+            })
+            .unwrap_or_else(|| StringSlice::from("Default"))
+    }
+
+    /// # Safety
+    /// The returned pointer must be freed
+    #[no_mangle]
+    pub extern "C" fn ASSSyllabeGetContent(this: &ASSSyllabe) -> StringSlice {
+        StringSlice::from(&this.content)
+    }
+
+    /// Load the ASS from a file, returns nullptr if an error was encountred.
+    #[no_mangle]
+    pub extern "C" fn ASSContainerFromFile(path: NonNull<c_char>) -> *mut ASSContainer {
+        match unsafe { CStr::from_ptr(path.as_ptr() as *const _) }.to_str() {
+            Ok(path) => ass_container_from_file(path)
+                .map(|ass| Box::into_raw(Box::new(ass)))
+                .unwrap_or_else(|err| {
+                    log::error!("failed to load file: {err}");
+                    std::ptr::null_mut()
+                }),
+            Err(err) => {
+                log::error!("invalid utf8 filename: {err}");
+                return std::ptr::null_mut();
+            }
+        }
+    }
+
+    #[no_mangle]
+    pub extern "C" fn ASSContainerGetStyleByName(this: &mut ASSContainer, name: *const c_char) -> *mut ASSStyle {
+        todo!()
+    }
+
+    #[no_mangle]
+    pub extern "C" fn ASSContainerGetStyleAt(this: &mut ASSContainer, idx: usize) -> *mut ASSStyle {
+        todo!()
+    }
+
+    #[no_mangle]
+    pub extern "C" fn ASSContainerGetStylesCount(this: &mut ASSContainer) -> usize {
+        todo!()
+    }
+
+    #[no_mangle]
+    pub extern "C" fn ASSLineSetStartTime(this: &mut ASSLine, time: i64) {}
+
+    #[no_mangle]
+    pub extern "C" fn ASSLineSetFiniTime(this: &mut ASSLine, time: i64) {}
+
+    /// Drop the container. It is file to pass a null pointer to this function.
+    /// # Safety
+    /// The use must ensure that no dangling references remains...
+    #[no_mangle]
+    pub extern "C" fn ASSContainerDrop(this: *mut ASSContainer) {
+        if !this.is_null() {
+            drop(unsafe { Box::from_raw(this) });
+        }
+    }
+}
diff --git a/src/Rust/vvs_lib/src/lib.rs b/src/Rust/vvs_lib/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..18305b8b8cc3fc613fa62a9de2bb7c053a5a0c04
--- /dev/null
+++ b/src/Rust/vvs_lib/src/lib.rs
@@ -0,0 +1,7 @@
+//! Here we define the things that will be exported to C/C++ code. We use PascalCase as it is not
+//! very common and getters must be of the form `{StructName}{Get,Set}{TheField}` and methods of
+//! the form `{StructName}{FunctionName}`. For free functions we use `{TheCrate}{FunctionName}`.
+
+#![allow(non_snake_case)]
+
+pub mod ass;
diff --git a/src/UI/AboutWindow.cc b/src/UI/AboutWindow.cc
index 307c09a2b4c48a84c098257b47756b25a7e9b070..b31788aedb0d2fa724a1605a8895e24eda8ec43a 100644
--- a/src/UI/AboutWindow.cc
+++ b/src/UI/AboutWindow.cc
@@ -9,12 +9,9 @@ using namespace Vivy;
 
 static const char *aboutContent =
     "<body>"
-    "  <p>Vivy is a replacement for Aegisub, writen in Qt5+and with less"
-    "     segfaults - hopefully.</p>"
-    "  <p>This software is licenced under the LGPL v3.0 or latter. The"
-    "     FakeVim part is imported from QtCreator, &copy; 2016 The Qt"
-    "     Company Ltd. and other contributors. Vivy is &copy; Vivy"
-    "     contributors.</p>"
+    "  <p>Vivy is a replacement for Aegisub, writen in Qt6 and with less segfaults - hopefully.</p>"
+    "  <p>This software (Vivy) is licenced under the LGPL v3.0 or latter and is &copy; Vivy contributors."
+    "     The libvvs library and vvcc compiler are MIT licenced and are &copy; 2023 Vivy contributors.</p>"
     "  <p>Contributors:<ul>"
     "    <li>Elliu</li>"
     "    <li>Kubat</li>"
@@ -25,8 +22,7 @@ static const char *libContent =
     "<body>"
     "  <p>Here are the libraries that where used to create the software:</p>"
     "  <ul>"
-    "    <li><a href=https://doc.qt.io/qt-5/index.html>Qt5</a> &copy; <i>2018 The Qt Company Ltd. and other contributors. (LGPL-V3)</i></li>"
-    "    <li><a href=https://www.lua.org>Lua 5.4</a> &copy; <i>1994–2021 Lua.org, PUC-Rio. (MIT)</i></li>"
+    "    <li><a href=https://doc.qt.io/qt-6/index.html>Qt6</a> &copy; <i>2023 The Qt Company Ltd. and other contributors. (LGPL-V3)</i></li>"
     "    <li><a href=https://libav.org>Libav</a> &copy; <i>Libav contributors. (LGPL-V2.1+)</i></li>"
     "  </ul>"
     "  <p>Other external dependencies where used:</p>"
diff --git a/src/UI/DocumentViews/AssLinesModel.cc b/src/UI/DocumentViews/AssLinesModel.cc
index 52d2490c87169dcfdfc1f7cc69275f237b35e211..a59240df393d5232e18c49d0444860508fa698d1 100644
--- a/src/UI/DocumentViews/AssLinesModel.cc
+++ b/src/UI/DocumentViews/AssLinesModel.cc
@@ -1,9 +1,10 @@
 #include "PreCompiledHeaders.hh"
+#include "Rust/VVLib.hh"
 #include "UI/DocumentViews/AssLinesModel.hh"
 
 using namespace Vivy;
 
-AssLinesModel::Item::Item(Ass::LineWeakPtr linePtr) noexcept
+AssLinesModel::Item::Item(VVLib::ASSLine *linePtr) noexcept
     : line(linePtr)
 {
 }
@@ -18,11 +19,10 @@ QString
 AssLinesModel::Item::getLineText() const noexcept
 {
     QString ret;
-    if (auto ptr = line.lock()) {
-        for (const auto &syl : ptr->getContent()) {
-            ret.append(syl.getContent());
-            ret.append("|");
-        }
+    for (size_t i = 0; i < VVLib::ASSLineGetSyllabesCount(line); i += 1) {
+        const auto str = VVLib::ASSSyllabeGetContent(VVLib::ASSLineGetSyllabeAt(line, i));
+        ret.append(std::string_view(str.str, str.len));
+        ret.append("|");
     }
     ret.remove(ret.size() - 1, 1);
     return ret;
@@ -31,28 +31,22 @@ AssLinesModel::Item::getLineText() const noexcept
 bool
 AssLinesModel::Item::getIsComment() const noexcept
 {
-    if (auto ptr = line.lock())
-        return ptr->getIsComment();
-    return false;
+    return VVLib::ASSLineIsCommented(line);
 }
 
 QString
 AssLinesModel::Item::getLineStyle() const noexcept
 {
-    if (auto ptr = line.lock()) {
-        if (auto style = ptr->getStyle().lock()) {
-            return style->getElementName();
-        }
-    }
-    return "";
+    const auto str = VVLib::ASSLineGetStyle(line);
+    return QString::fromUtf8(str.str, static_cast<qsizetype>(str.len));
 }
 
-AssLinesModel::AssLinesModel(const QVector<Ass::LinePtr> &lines) noexcept
+AssLinesModel::AssLinesModel(const QVector<VVLib::ASSLine *> &lines) noexcept
     : lineRealData(lines)
 {
     childs.reserve(lines.count());
-    for (const Ass::LinePtr &line : lines)
-        childs.append(new Item(Ass::LineWeakPtr{ line }));
+    for (VVLib::ASSLine *line : lines)
+        childs.append(new Item(line));
 }
 
 AssLinesModel::~AssLinesModel() noexcept { qDeleteAll(childs); }
diff --git a/src/UI/DocumentViews/AssLinesModel.hh b/src/UI/DocumentViews/AssLinesModel.hh
index bd55c1beadb52f7af47aeb3fd4475adba0abebe2..10a4b10c9427e83a31df6118382ec9c45bd22f72 100644
--- a/src/UI/DocumentViews/AssLinesModel.hh
+++ b/src/UI/DocumentViews/AssLinesModel.hh
@@ -2,7 +2,7 @@
 
 #include "PreCompiledHeaders.hh"
 #include "Lib/Utils.hh"
-#include "Lib/Ass/Ass.hh"
+#include "Rust/VVLib.hh"
 
 namespace Vivy
 {
@@ -15,7 +15,7 @@ private:
         VIVY_UNMOVABLE_OBJECT(Item)
 
     public:
-        Item(Ass::LineWeakPtr linePtr) noexcept;
+        Item(VVLib::ASSLine *linePtr) noexcept;
         ~Item() noexcept = default;
 
         enum class Field : int {
@@ -29,13 +29,13 @@ private:
         QString getLineStyle() const noexcept;
 
     private:
-        Ass::LineWeakPtr line;
+        VVLib::ASSLine *line;
     };
 
     static inline const QStringList headers{ "", "Style", "Text" };
 
 public:
-    explicit AssLinesModel(const QVector<Ass::LinePtr> &) noexcept;
+    explicit AssLinesModel(const QVector<VVLib::ASSLine *> &) noexcept;
     ~AssLinesModel() noexcept override;
 
     QVariant data(const QModelIndex &, int role) const noexcept override;
@@ -52,6 +52,6 @@ public:
 
 private:
     QVector<Item *> childs;
-    const QVector<Ass::LinePtr> &lineRealData;
+    const QVector<VVLib::ASSLine *> &lineRealData;
 };
 }
diff --git a/src/UI/DocumentViews/TimingScene.cc b/src/UI/DocumentViews/TimingScene.cc
index c438efa4f83e847cce97d96cb084fb77c6039d79..268bc0f627e85aeccef1fcab5aa40ac8b7c3d3cf 100644
--- a/src/UI/DocumentViews/TimingScene.cc
+++ b/src/UI/DocumentViews/TimingScene.cc
@@ -23,11 +23,12 @@ TimingScene::TimingScene(QWidget *parent) noexcept
 
 TimingScene::TimingScene(QImage img_, quint64 soundLength_, QWidget *parent) noexcept
     : QGraphicsScene(parent)
+    , backgroundImg(addPixmap(QPixmap::fromImage(img_)))
     , img(img_)
-    , soundLength(soundLength_)
+    , soundLength(
+          static_cast<qint64>(std::clamp(soundLength_, static_cast<quint64>(0),
+                                         static_cast<quint64>(std::numeric_limits<qint64>::max()))))
 {
-    QPixmap pixmap(QPixmap::fromImage(img));
-    backgroundImg = addPixmap(pixmap);
 }
 
 void
@@ -35,52 +36,49 @@ TimingScene::mousePressEvent(QGraphicsSceneMouseEvent *event) noexcept
 {
     QPointF pos        = event->scenePos();
     QGraphicsItem *got = itemAt(pos, QTransform());
-    Ass::LinePtr p     = currentLine.lock();
 
-    if (p && (got == nullptr || got == backgroundImg)) [[likely]] {
+    if (currentLine && (got == nullptr || got == backgroundImg)) [[likely]] {
         // Handle the different cases
         if (timingMode == TimingMode::Line)
-            handleMousePressEventLine(event, p);
+            handleMousePressEventLine(event, currentLine);
         else if (timingMode == TimingMode::Syl)
-            handleMousePressEventSyl(event, p);
+            handleMousePressEventSyl(event, currentLine);
         else if (timingMode == TimingMode::Char)
-            handleMousePressEventChar(event, p);
+            handleMousePressEventChar(event, currentLine);
     }
 
     QGraphicsScene::mousePressEvent(event);
 }
 
 void
-TimingScene::handleMousePressEventLine(QGraphicsSceneMouseEvent *event, Ass::LinePtr p) noexcept
+TimingScene::handleMousePressEventLine(QGraphicsSceneMouseEvent *event, VVLib::ASSLine p[]) noexcept
 {
-    QPointF pos  = event->scenePos();
-    quint64 time = timeFromPos(pos.x());
-
+    const qint64 time = timeFromPos(event->scenePos().x());
     if (const auto &btn = event->button(); btn == Qt::LeftButton) {
-        p->setStart(time);
+        VVLib::ASSLineSetStartTime(p, static_cast<int64_t>(time));
     } else if (btn == Qt::RightButton) {
-        p->setEnd(time);
+        VVLib::ASSLineSetFiniTime(p, static_cast<int64_t>(time));
     }
 }
 
 void
-TimingScene::handleMousePressEventSyl(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept
+TimingScene::handleMousePressEventSyl(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept
 {
 }
 
 void
-TimingScene::handleMousePressEventChar(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept
+TimingScene::handleMousePressEventChar(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept
 {
 }
 
-quint64
+qint64
 TimingScene::timeFromPos(qreal x)
 {
     if (const qreal w = width(); x <= 0 || w <= 0) {
         qCritical() << "Try avoid possible divide by zero in the time from position";
         return 0;
     } else {
-        return static_cast<quint64>(x) * soundLength / static_cast<quint64>(w);
+        return static_cast<qint64>(x) * soundLength / static_cast<qint64>(w);
     }
 }
 
diff --git a/src/UI/DocumentViews/TimingScene.hh b/src/UI/DocumentViews/TimingScene.hh
index 1d28e61afaf136d08260e2970b679260672f986a..7bb841cbdcead04be41e603d9f28db525764d477 100644
--- a/src/UI/DocumentViews/TimingScene.hh
+++ b/src/UI/DocumentViews/TimingScene.hh
@@ -1,7 +1,7 @@
 #pragma once
 
 #include "Lib/Utils.hh"
-#include "Lib/Ass/Ass.hh"
+#include "Rust/VVLib.hh"
 #include "UI/DocumentViews/TimingBar.hh"
 
 namespace Vivy
@@ -23,8 +23,8 @@ public:
 private:
     QGraphicsPixmapItem *backgroundImg{ nullptr };
     QImage img;
-    quint64 soundLength{ 0 };
-    Ass::LineWeakPtr currentLine{};
+    qint64 soundLength{ 0 };
+    VVLib::ASSLine *currentLine{ nullptr };
     TimingMode timingMode{ TimingMode::Line };
 
 public:
@@ -32,10 +32,10 @@ public:
     void mousePressEvent(QGraphicsSceneMouseEvent *event) noexcept override;
 
 private:
-    quint64 timeFromPos(qreal x);
-    void handleMousePressEventLine(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept;
-    void handleMousePressEventSyl(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept;
-    void handleMousePressEventChar(QGraphicsSceneMouseEvent *, Ass::LinePtr) noexcept;
+    qint64 timeFromPos(qreal x);
+    void handleMousePressEventLine(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept;
+    void handleMousePressEventSyl(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept;
+    void handleMousePressEventChar(QGraphicsSceneMouseEvent *, VVLib::ASSLine[]) noexcept;
 
 public slots:
 };
diff --git a/utils/scripts/build-libvvs.bash b/utils/scripts/build-libvvs.bash
new file mode 100755
index 0000000000000000000000000000000000000000..0dd55e638cbeba2e0b1c85752c45a9ea1f09e2a3
--- /dev/null
+++ b/utils/scripts/build-libvvs.bash
@@ -0,0 +1,13 @@
+#!/bin/sh
+set -e
+exec 5>&1
+cd "$(git rev-parse --show-toplevel)"
+
+FILES=$(cargo build --manifest-path src/Rust/Cargo.toml --workspace ${2} --message-format=json \
+    | jq -r 'select( .reason == "compiler-artifact" and ((.target.kind | index("staticlib")) or (.target.kind | index("bin"))) ) .filenames[0]' \
+    | tee >(cat - >&5))
+
+for FILE in ${FILES}; do
+    FILE=${FILE}
+    cp -u ${FILE} "${1}/$(basename ${FILE})"
+done
diff --git a/utils/scripts/count-lines.bash b/utils/scripts/count-lines.bash
new file mode 100755
index 0000000000000000000000000000000000000000..f52e7367c600dbe109c13b936ad4cf02607ff09a
--- /dev/null
+++ b/utils/scripts/count-lines.bash
@@ -0,0 +1,4 @@
+#!/bin/bash
+set -xe
+cd "$(git rev-parse --show-toplevel)"
+cloc --vcs=git
diff --git a/utils/scripts/count-lines.sh b/utils/scripts/count-lines.sh
deleted file mode 100755
index 4971cb7efaf75756eee35cf14fdc94818e52e90a..0000000000000000000000000000000000000000
--- a/utils/scripts/count-lines.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-set -xe
-_ROOT="$(git rev-parse --show-toplevel)"
-cd "$_ROOT"
-cloc --vcs=git
diff --git a/utils/scripts/icons.bash b/utils/scripts/icons.bash
index 91f277df4a4c2ae5ce3da2f131b21afe01200ae3..a453d1b10c51b6f79c590e19b522c7e1fe678b03 100755
--- a/utils/scripts/icons.bash
+++ b/utils/scripts/icons.bash
@@ -1,5 +1,7 @@
 #!/bin/bash
 
+cd "$(git rev-parse --show-toplevel)"
+
 COUNTER=0
 FILE=utils/rsc/VivyPartialIcons.tmp
 
diff --git a/utils/scripts/tidy.bash b/utils/scripts/tidy.bash
deleted file mode 100755
index 5873d272f01c7ac212cc9f2b84bc4a11deda2b53..0000000000000000000000000000000000000000
--- a/utils/scripts/tidy.bash
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/bin/bash
-
-if [ ! -f compile_commands.json ]
-then
-    echo "Did you use cmake with the '-DCMAKE_EXPORT_COMPILE_COMMANDS=ON'"
-    echo "option and copy the 'compile_commands.json' into the project's"
-    echo "root folder?"
-    exit 1
-fi
-
-INCLUDES=""
-UNAME=$(uname -a)
-
-# Detect Qt headers, you may add support for your distribution
-uname -a | egrep -i 'ubuntu|debian' 2>/dev/null >/dev/null
-if [ $? -eq 0 ]
-then
-    INCLUDES="-I/usr/include/x86_64-linux-gnu/qt5/QtCore -I/usr/include/x86_64-linux-gnu/qt5/QtWidgets"
-    echo "Using debian/ubuntu Qt header locations"
-fi
-
-find src -name '*.cc' -exec clang-tidy {} -fix-errors -checks=modernize-* -- -std=c++20 $INCLUDES \;
-find src -name '*.cc' -exec clang-tidy {} -fix-errors -checks=abseil-*    -- -std=c++20 $INCLUDES \;
-find src -name '*.cc' -exec clang-tidy {} -fix-errors -checks=bugprone-*  -- -std=c++20 $INCLUDES \;
diff --git a/vendor/README.md b/vendor/README.md
deleted file mode 100644
index 6928ae7fd0650d5c8f39742727df2faa12558325..0000000000000000000000000000000000000000
--- a/vendor/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-# How to add new third party libraries
-
-1. Check the licence compatibility
-2. Extract the archive in this folder
-3. Add a `CMakeLists.txt` to be able to compile and link this library
-   with Vivy.
-
-Here is a sample `CMakeLists.txt` file for lua:
-
-```cmake
-cmake_minimum_required(VERSION 3.5)
-project(lua VERSION 5.4.3 LANGUAGES C)
-
-if(WIN32)
-    add_definitions(-D_CRT_SECURE_NO_WARNINGS)
-endif()
-
-# Lua static library
-add_library(lualib STATIC
-    lapi.c lcode.c lctype.c ldebug.c ldo.c ldump.c lfunc.c lgc.c
-    llex.c lmem.c lobject.c lopcodes.c lparser.c lstate.c lstring.c
-    ltable.c ltm.c lundump.c lvm.c lzio.c lauxlib.c lbaselib.c
-    lbitlib.c lcorolib.c ldblib.c liolib.c lmathlib.c loslib.c
-    lstrlib.c ltablib.c loadlib.c linit.c
-)
-set_target_properties(lualib PROPERTIES OUTPUT_NAME "lua")
-
-# Lua interpreter
-link_directories(${LUA_BINARY_DIR})
-add_executable(lua lua.c)
-target_link_libraries(lua PRIVATE lualib)
-if(UNIX)
-    target_link_libraries(lua m)
-endif()
-
-# Lua compiler
-link_directories(${LUA_BINARY_DIR})
-add_executable(luac luac.c)
-target_link_libraries(luac lualib)
-if(UNIX)
-    target_link_libraries(luac m)
-endif()
-```