Skyrim has the largest modding ecosystem in PC gaming. This document outlines how OpenSkyrim handles legacy Skyrim mods (.esp, .esm, .esl, .bsa, mesh/texture overrides, Papyrus scripts) while introducing modern, native Lua modding.
┌───────────────────────────────┐
│ Modder / User Setup │
│ (VORTEX / MO2 / Data Dir) │
└───────────────┬───────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ OpenSkyrim Mod Ingestion & Sandbox │
│ │
│ ┌─────────────────────────────────┐ ┌───────────────────────────────┐ │
│ │ Tier 1: Legacy Compatibility │ │ Tier 2: Native Modern Mods │ │
│ │ - Unpack `.esp`/`.esl` to DB │ │ - Direct glTF / KTX2 Assets │ │
│ │ - On-the-fly .nif/.dds convert │ │ - Native Luau Scripts │ │
│ │ - Papyrus > Lua Transpilation │ │ - Hot-reloading & Sandboxing │ │
│ └─────────────────────────────────┘ └───────────────────────────────┘ │
└──────────────────────────────────────────────┬──────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ Unified OpenSkyrim Engine Runtime │
│ (Virtual Filesystem + SQLite Mod Layering) │
└─────────────────────────────────────────────────────────────────────────────┘
In original Skyrim, .esp files override records from Skyrim.esm based on load order (e.g. plugins.txt).
- SQLite Mod Layering:
- OpenSkyrim stores base game data in
skyrim_world.db. - When a user adds an
.espmod, the converter imports the plugin's records into a mod table with a higher load order priority weight. - Database query:
SELECT * FROM refr_objects WHERE form_id = ? ORDER BY load_order DESC LIMIT 1;
- Benefit: Instant record resolution with zero engine hacking required!
- OpenSkyrim stores base game data in
- Mods containing loose
.nifor.ddsfiles are detected by the Virtual Filesystem (VFS). - The converter transpiles mod
.niffiles to.glband.ddstextures to.ktx2in a local cache directory (mod_cache/).
.pexbytecode contained within mod.bsaarchives orScripts/folders is run through the Papyrus-to-Lua AST Transpiler.- Mod functions call the unified OpenSkyrim Lua API bindings seamlessly.
Instead of relying solely on external tools, OpenSkyrim includes a Built-in Mod Manager inside the Launcher.
OpenSkyrim/
├── game_data/ # Unpacked base game & DLC assets
├── transformed_data/ # Transformed base game (glTF, KTX2, SQLite)
├── mods/ # User installed raw mod folders (installed via Launcher)
│ ├── ModA_HighResArmor/
│ └── ModB_CustomQuest/
├── transformed_mods/ # Transformed mod cache (glTF, KTX2, Lua)
└── config.json # Mod load order & active plugin list
- Drag-and-Drop Installation: Drop
.zip/.7z/.rarmod archives directly into the Launcher. - Visual Load Order Manager: Drag and drop
.esp/.eslload order priorities with conflict detection. - One-Click Transformation: Clicking "Enable Mod" automatically runs the asset converter for that mod into
transformed_mods/.
Original Skyrim uses Autodesk Scaleform, which executes Adobe Flash (.swf / .gfx files with ActionScript 2.0). Flash is obsolete, insecure, and heavily limits UI customization and performance.
OpenSkyrim completely eliminates webviews, embedded browser engines, and Flash runtimes. All UI elements (hud, menus, inventory, dialogue choices) are transpiled directly into native Bevy 0.19 bsn! (Bevy Scene Notation) declarative widget trees for pure zero-overhead GPU execution.
┌───────────────────────────┐
│ Original Skyrim Flash UI │
│ (.swf / .gfx Scaleform) │
└─────────────┬─────────────┘
│
▼ (Offline Flash/Scaleform Transpiler)
┌─────────────────────────────────────────────────────────────────────────────┐
│ Bevy 0.19 `bsn!` Declarative UI Tree │
│ ┌──────────────────────────┬──────────────────────┬─────────────────────┐ │
│ │ `bsn!` Node Structure │ Bevy UI Styles │ Luau UI Handlers │ │
│ │ (Native Bevy Widgets) │ (Color / Typography)│ (ActionScript > Luau) │ │
│ └──────────────────────────┴──────────────────────┴─────────────────────┘ │
└─────────────────────────────┬───────────────────────────────────────────────┘
│
▼ (Pure GPU Native Execution)
┌─────────────────────────────────────────────────────────────────────────────┐
│ Bevy Engine Render Pipeline │
│ │
│ Native Bevy UI System (Zero Webview / Zero Embedded Engine Overhead) │
│ - Direct Bevy ECS Query & Mutator System Integration │
│ - Sub-millisecond rendering & frame-rate uncapped GPU drawing │
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Bevy ECS Bridge: UI Events < Direct ECS Events > Luau / Engine │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
-
Flash Extraction & AST Transpilation (Offline Phase):
- Flash Layouts ➔
bsn!Widgets: Vector shapes, buttons, text fields, and container layouts inside.swf/.gfxare exported (via AST extraction inopenskyrim_converter) and transpiled into native Bevy UI nodes usingbsn!declarative syntax. - ActionScript 2.0 ➔ Unified Luau Handlers: ActionScript UI scripts (e.g. inventory filtering, stats calculations, menu navigation) are transpiled into standard Luau functions. OpenSkyrim uses Luau as the single, unified scripting engine for both UI handlers and quest/game logic—eliminating secondary UI scripting runtimes.
- Flash Layouts ➔
-
Rendering & Execution inside Bevy (Runtime Phase):
- Bevy 0.19
bsn!Native UI:- UI layout structures load directly into native Bevy 0.19
bsn!widget trees. bsn!provides clean, patchable UI widget trees with automatic asset dependency management directly in Rust/Bevy without requiring any browser runtimes, webview overhead, or HTML rendering libraries.
- UI layout structures load directly into native Bevy 0.19
- Bevy 0.19
-
Direct ECS Event Integration (UI ↔ Bevy ECS ↔ Luau Engine):
- Interacting with UI widgets triggers standard Bevy ECS events directly in Rust.
- Game state updates (e.g. player health changes, item acquisitions) instantly mutate Bevy UI components without IPC serialization overhead.
on (release) {
_root.EquipItem(this.itemID);
this.gotoAndStop("Equipped");
}local InventoryUI = {}
function InventoryUI:onItemSlotReleased(slot)
Engine.Player:equipItem(slot.itemID)
slot:setState("Equipped")
end
return InventoryUIuse bevy::prelude::*;
// Transpiled from InventoryMenu.gfx to Bevy 0.19 bsn!
pub fn spawn_inventory_menu(mut commands: Commands, assets: Res<AssetServer>) {
commands.spawn(bsn! {
Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
justify_content: JustifyContent::SpaceBetween,
..default()
} [
// Left Side: Inventory Item List Container
Node {
width: Val::Px(400.0),
flex_direction: FlexDirection::Column,
background_color: Color::srgb(0.05, 0.05, 0.05).into(),
..default()
} [
Text::new("INVENTORY"),
ButtonNode {
border: UiRect::all(Val::Px(1.0)),
..default()
} [
Text::new("Iron Longsword"),
]
],
// Right Side: Item 3D Preview Frame
Node {
width: Val::Px(500.0),
height: Val::Px(500.0),
..default()
}
]
});
}