diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index daa0365f..34f851f6 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -46,6 +46,9 @@ jobs:
libglm-dev \
libssl-dev \
zlib1g-dev \
+ libvulkan-dev \
+ vulkan-tools \
+ glslc \
libavformat-dev \
libavcodec-dev \
libswscale-dev \
@@ -89,14 +92,14 @@ jobs:
- name: Install dependencies
run: |
brew install cmake pkg-config sdl2 glew glm openssl@3 zlib ffmpeg unicorn \
- stormlib dylibbundler || true
+ stormlib vulkan-loader vulkan-headers shaderc dylibbundler || true
# dylibbundler may not be in all brew mirrors; install separately to not block others
brew install dylibbundler 2>/dev/null || true
- name: Configure
run: |
BREW=$(brew --prefix)
- export PKG_CONFIG_PATH="$BREW/lib/pkgconfig:$(brew --prefix ffmpeg)/lib/pkgconfig:$(brew --prefix openssl@3)/lib/pkgconfig"
+ export PKG_CONFIG_PATH="$BREW/lib/pkgconfig:$(brew --prefix ffmpeg)/lib/pkgconfig:$(brew --prefix openssl@3)/lib/pkgconfig:$(brew --prefix vulkan-loader)/lib/pkgconfig:$(brew --prefix shaderc)/lib/pkgconfig"
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_PREFIX_PATH="$BREW" \
@@ -170,7 +173,7 @@ jobs:
uses: msys2/setup-msys2@v2
with:
msystem: CLANGARM64
- update: false
+ update: true
install: >-
mingw-w64-clang-aarch64-cmake
mingw-w64-clang-aarch64-clang
@@ -182,8 +185,16 @@ jobs:
mingw-w64-clang-aarch64-openssl
mingw-w64-clang-aarch64-zlib
mingw-w64-clang-aarch64-ffmpeg
+ mingw-w64-clang-aarch64-unicorn
+ mingw-w64-clang-aarch64-vulkan-loader
+ mingw-w64-clang-aarch64-vulkan-headers
+ mingw-w64-clang-aarch64-shaderc
git
+ - name: Install optional packages
+ shell: msys2 {0}
+ run: pacman -S --noconfirm --needed mingw-w64-clang-aarch64-stormlib || true
+
- name: Configure
shell: msys2 {0}
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
@@ -237,9 +248,16 @@ jobs:
mingw-w64-x86_64-zlib
mingw-w64-x86_64-ffmpeg
mingw-w64-x86_64-unicorn
+ mingw-w64-x86_64-vulkan-loader
+ mingw-w64-x86_64-vulkan-headers
+ mingw-w64-x86_64-shaderc
mingw-w64-x86_64-nsis
git
+ - name: Install optional packages
+ shell: msys2 {0}
+ run: pacman -S --noconfirm --needed mingw-w64-x86_64-stormlib || true
+
- name: Configure
shell: msys2 {0}
run: cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml
index 8dd2183d..91296a97 100644
--- a/.github/workflows/security.yml
+++ b/.github/workflows/security.yml
@@ -36,6 +36,9 @@ jobs:
libglm-dev \
libssl-dev \
zlib1g-dev \
+ libvulkan-dev \
+ vulkan-tools \
+ glslc \
libavformat-dev \
libavcodec-dev \
libswscale-dev \
@@ -105,6 +108,9 @@ jobs:
libglm-dev \
libssl-dev \
zlib1g-dev \
+ libvulkan-dev \
+ vulkan-tools \
+ glslc \
libavformat-dev \
libavcodec-dev \
libswscale-dev \
diff --git a/.gitignore b/.gitignore
index 1ece92da..f95c18ed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -42,10 +42,12 @@ wowee
*~
.DS_Store
-# External dependencies (except submodules)
+# External dependencies (except submodules and vendored headers)
extern/*
!extern/.gitkeep
!extern/imgui
+!extern/vk-bootstrap
+!extern/vk_mem_alloc.h
# ImGui state
imgui.ini
@@ -64,7 +66,7 @@ cache/
saves/
wowee_[0-9][0-9][0-9][0-9]
-# Extracted assets (run ./extract_assets.sh to generate)
+# Extracted assets (run ./extract_assets.sh or .\extract_assets.ps1 to generate)
Data/db/
Data/character/
Data/creature/
@@ -87,6 +89,9 @@ Data/expansions/*/overlay/
Data/hd/
ingest/
+# Asset pipeline state and texture packs
+asset_pipeline/
+
# Local texture dumps / extracted art should never be committed
assets/textures/
node_modules/
diff --git a/.gitmodules b/.gitmodules
index d8eaaa16..84acc55c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -2,3 +2,7 @@
path = extern/imgui
url = https://github.com/ocornut/imgui.git
shallow = true
+[submodule "extern/vk-bootstrap"]
+ path = extern/vk-bootstrap
+ url = https://github.com/charles-lunarg/vk-bootstrap.git
+ shallow = true
diff --git a/BUILD_INSTRUCTIONS.md b/BUILD_INSTRUCTIONS.md
index bd1a09a7..37fb3b3f 100644
--- a/BUILD_INSTRUCTIONS.md
+++ b/BUILD_INSTRUCTIONS.md
@@ -10,7 +10,13 @@ This document provides platform-specific build instructions for WoWee.
```bash
sudo apt update
-sudo apt install -y build-essential cmake pkg-config git libsdl2-dev libglew-dev libglm-dev libssl-dev zlib1g-dev libavcodec-dev libavformat-dev libavutil-dev libswscale-dev libunicorn-dev libstorm-dev
+sudo apt install -y \
+ build-essential cmake pkg-config git \
+ libsdl2-dev libglew-dev libglm-dev \
+ libssl-dev zlib1g-dev \
+ libvulkan-dev vulkan-tools glslc \
+ libavcodec-dev libavformat-dev libavutil-dev libswscale-dev \
+ libunicorn-dev libstorm-dev libx11-dev
```
---
@@ -20,7 +26,11 @@ sudo apt install -y build-essential cmake pkg-config git libsdl2-dev libglew
### Install Dependencies
```bash
-sudo pacman -S --needed base-devel cmake pkgconf git sdl2 glew glm openssl zlib ffmpeg unicorn stormlib
+sudo pacman -S --needed \
+ base-devel cmake pkgconf git \
+ sdl2 glew glm openssl zlib \
+ vulkan-devel vulkan-tools shaderc \
+ ffmpeg unicorn stormlib
```
---
@@ -49,15 +59,119 @@ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j"$(nproc)"
```
+### Asset Extraction (Linux)
+
+After building, extract assets from your WoW client:
+
+```bash
+./extract_assets.sh /path/to/WoW/Data wotlk
+```
+
+Supports `classic`, `tbc`, `wotlk` targets (auto-detected if omitted).
+
+---
+
+## 🍎 macOS
+
+### Install Dependencies
+
+Vulkan on macOS is provided via MoltenVK (a Vulkan-to-Metal translation layer),
+which is included in the `vulkan-loader` Homebrew package.
+
+```bash
+brew install cmake pkg-config sdl2 glew glm openssl@3 zlib ffmpeg unicorn \
+ stormlib vulkan-loader vulkan-headers shaderc
+```
+
+Optional (for creating redistributable `.app` bundles):
+
+```bash
+brew install dylibbundler
+```
+
+### Clone & Build
+
+```bash
+git clone --recurse-submodules https://github.com/Kelsidavis/WoWee.git
+cd WoWee
+
+BREW=$(brew --prefix)
+export PKG_CONFIG_PATH="$BREW/lib/pkgconfig:$(brew --prefix ffmpeg)/lib/pkgconfig:$(brew --prefix openssl@3)/lib/pkgconfig:$(brew --prefix vulkan-loader)/lib/pkgconfig:$(brew --prefix shaderc)/lib/pkgconfig"
+cmake -S . -B build -DCMAKE_BUILD_TYPE=Release \
+ -DCMAKE_PREFIX_PATH="$BREW" \
+ -DOPENSSL_ROOT_DIR="$(brew --prefix openssl@3)"
+cmake --build build -j"$(sysctl -n hw.logicalcpu)"
+```
+
+### Asset Extraction (macOS)
+
+The script will auto-build `asset_extract` if needed (requires `stormlib`).
+It automatically detects Homebrew and passes the correct paths to CMake.
+
+```bash
+./extract_assets.sh /path/to/WoW/Data wotlk
+```
+
+Supports `classic`, `tbc`, `wotlk` targets (auto-detected if omitted).
+
+---
+
+## 🪟 Windows (MSYS2 — Recommended)
+
+MSYS2 provides all dependencies as pre-built packages.
+
+### Install MSYS2
+
+Download and install from , then open a **MINGW64** shell.
+
+### Install Dependencies
+
+```bash
+pacman -S --needed \
+ mingw-w64-x86_64-cmake \
+ mingw-w64-x86_64-gcc \
+ mingw-w64-x86_64-ninja \
+ mingw-w64-x86_64-pkgconf \
+ mingw-w64-x86_64-SDL2 \
+ mingw-w64-x86_64-glew \
+ mingw-w64-x86_64-glm \
+ mingw-w64-x86_64-openssl \
+ mingw-w64-x86_64-zlib \
+ mingw-w64-x86_64-ffmpeg \
+ mingw-w64-x86_64-unicorn \
+ mingw-w64-x86_64-vulkan-loader \
+ mingw-w64-x86_64-vulkan-headers \
+ mingw-w64-x86_64-shaderc \
+ mingw-w64-x86_64-stormlib \
+ git
+```
+
+### Clone & Build
+
+```bash
+git clone --recurse-submodules https://github.com/Kelsidavis/WoWee.git
+cd WoWee
+cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
+cmake --build build --parallel $(nproc)
+```
+
---
## 🪟 Windows (Visual Studio 2022)
+For users who prefer Visual Studio over MSYS2.
+
### Install
-- Visual Studio 2022
-- Desktop development with C++
-- CMake tools for Windows
+- Visual Studio 2022 with **Desktop development with C++** workload
+- CMake tools for Windows (included in VS workload)
+- [LunarG Vulkan SDK](https://vulkan.lunarg.com/) (provides Vulkan headers, loader, and glslc)
+
+### vcpkg Dependencies
+
+```powershell
+vcpkg install sdl2 glew glm openssl zlib ffmpeg stormlib --triplet x64-windows
+```
### Clone
@@ -68,16 +182,29 @@ cd WoWee
### Build
-Open the folder in Visual Studio (it will detect CMake automatically)
+Open the folder in Visual Studio (it will detect CMake automatically)
or build from Developer PowerShell:
```powershell
-cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
+cmake -S . -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE="[vcpkg root]/scripts/buildsystems/vcpkg.cmake"
cmake --build build --config Release
```
---
+## 🪟 Asset Extraction (Windows)
+
+After building (via either MSYS2 or Visual Studio), extract assets from your WoW client:
+
+```powershell
+.\extract_assets.ps1 "C:\Games\WoW-3.3.5a\Data"
+```
+
+Or double-click `extract_assets.bat` and provide the path when prompted.
+You can also specify an expansion: `.\extract_assets.ps1 "C:\Games\WoW\Data" wotlk`
+
+---
+
## ⚠️ Notes
- Case matters on Linux (`WoWee` not `wowee`).
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2999b38c..fe58f6c2 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -35,7 +35,30 @@ endif()
# Find required packages
find_package(SDL2 REQUIRED)
-find_package(Vulkan REQUIRED)
+find_package(Vulkan QUIET)
+if(NOT Vulkan_FOUND)
+ # Fallback: some distros / CMake versions need pkg-config to locate Vulkan.
+ find_package(PkgConfig QUIET)
+ if(PkgConfig_FOUND)
+ pkg_check_modules(VULKAN_PKG vulkan)
+ if(VULKAN_PKG_FOUND)
+ add_library(Vulkan::Vulkan INTERFACE IMPORTED)
+ set_target_properties(Vulkan::Vulkan PROPERTIES
+ INTERFACE_INCLUDE_DIRECTORIES "${VULKAN_PKG_INCLUDE_DIRS}"
+ INTERFACE_LINK_LIBRARIES "${VULKAN_PKG_LIBRARIES}"
+ )
+ if(VULKAN_PKG_LIBRARY_DIRS)
+ set_property(TARGET Vulkan::Vulkan APPEND PROPERTY
+ INTERFACE_LINK_DIRECTORIES "${VULKAN_PKG_LIBRARY_DIRS}")
+ endif()
+ set(Vulkan_FOUND TRUE)
+ message(STATUS "Found Vulkan via pkg-config: ${VULKAN_PKG_LIBRARIES}")
+ endif()
+ endif()
+ if(NOT Vulkan_FOUND)
+ message(FATAL_ERROR "Could not find Vulkan. Install libvulkan-dev (Linux), vulkan-loader (macOS), or the Vulkan SDK (Windows).")
+ endif()
+endif()
# GL/GLEW kept temporarily for unconverted sub-renderers during Vulkan migration.
# These files compile against GL types but their code is never called — the Vulkan
# path is the only active rendering backend. Remove in Phase 7 when all renderers
@@ -445,6 +468,9 @@ endif()
target_include_directories(wowee PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/src
+)
+# Vendored headers as SYSTEM to suppress third-party warnings
+target_include_directories(wowee SYSTEM PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/extern
${CMAKE_CURRENT_SOURCE_DIR}/extern/vk-bootstrap/src
)
@@ -522,7 +548,7 @@ endif()
if(MSVC)
target_compile_options(wowee PRIVATE /W4)
else()
- target_compile_options(wowee PRIVATE -Wall -Wextra -Wpedantic)
+ target_compile_options(wowee PRIVATE -Wall -Wextra -Wpedantic -Wno-missing-field-initializers)
endif()
# Debug build flags
@@ -594,12 +620,18 @@ add_custom_command(TARGET wowee POST_BUILD
# which does NOT include System32. Copy vulkan-1.dll into the output directory so
# SDL_Vulkan_LoadLibrary can locate it without needing a full system PATH search.
if(WIN32)
- add_custom_command(TARGET wowee POST_BUILD
- COMMAND ${CMAKE_COMMAND} -E copy_if_different
- "$ENV{SystemRoot}/System32/vulkan-1.dll"
- "$/vulkan-1.dll"
- COMMENT "Copying vulkan-1.dll to output directory"
- )
+ find_file(VULKAN_DLL vulkan-1.dll
+ PATHS "$ENV{SystemRoot}/System32" "$ENV{VULKAN_SDK}/Bin"
+ NO_DEFAULT_PATH)
+ if(VULKAN_DLL)
+ add_custom_command(TARGET wowee POST_BUILD
+ COMMAND ${CMAKE_COMMAND} -E copy_if_different
+ "${VULKAN_DLL}" "$/vulkan-1.dll"
+ COMMENT "Copying vulkan-1.dll to output directory"
+ )
+ else()
+ message(STATUS " vulkan-1.dll not found — skipping copy (MSYS2 provides it via PATH)")
+ endif()
endif()
# Install targets
@@ -661,7 +693,14 @@ if(STORMLIB_LIBRARY AND STORMLIB_INCLUDE_DIR)
Threads::Threads
)
if(WIN32)
- target_link_libraries(asset_extract PRIVATE wininet bz2)
+ find_library(WININET_LIB wininet)
+ find_library(BZ2_LIB bz2)
+ if(WININET_LIB)
+ target_link_libraries(asset_extract PRIVATE ${WININET_LIB})
+ endif()
+ if(BZ2_LIB)
+ target_link_libraries(asset_extract PRIVATE ${BZ2_LIB})
+ endif()
endif()
set_target_properties(asset_extract PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
diff --git a/README.md b/README.md
index debe3d16..6a91237c 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@ Protocol Compatible with **Vanilla (Classic) 1.12 + TBC 2.4.3 + WotLK 3.3.5a**.
### Asset Pipeline
- Extracted loose-file **`Data/`** tree indexed by **`manifest.json`** (fast lookup + caching)
- Optional **overlay layers** for multi-expansion asset deduplication
-- `asset_extract` + `extract_assets.sh` for MPQ extraction (StormLib tooling)
+- `asset_extract` + `extract_assets.sh` (Linux/macOS) / `extract_assets.ps1` (Windows) for MPQ extraction (StormLib tooling)
- File formats: **BLP** (DXT1/3/5), **ADT**, **M2**, **WMO**, **DBC** (Spell/Item/Faction/etc.)
### Gameplay Systems
@@ -84,6 +84,14 @@ sudo pacman -S sdl2 glm openssl \
ffmpeg zlib cmake base-devel libx11 \
unicorn # optional: Warden module execution
# StormLib: install from AUR for asset_extract tool
+
+# macOS (Homebrew)
+brew install cmake pkg-config sdl2 glew glm openssl@3 zlib ffmpeg \
+ vulkan-loader vulkan-headers shaderc \
+ unicorn \
+ stormlib
+# unicorn is optional (Warden module execution)
+# stormlib is optional (asset_extract tool)
```
### Container build
@@ -98,11 +106,18 @@ This project requires WoW client data that you extract from your own legally obt
Wowee loads assets via an extracted loose-file tree indexed by `manifest.json` (it does not read MPQs at runtime).
+For a cross-platform GUI workflow (extraction + texture pack management + active override state), see:
+- [Asset Pipeline GUI](docs/asset-pipeline-gui.md)
+
#### 1) Extract MPQs into `./Data/`
```bash
-# WotLK 3.3.5a example
+# Linux / macOS
./extract_assets.sh /path/to/WoW/Data wotlk
+
+# Windows (PowerShell)
+.\extract_assets.ps1 "C:\Games\WoW-3.3.5a\Data" wotlk
+# Or double-click extract_assets.bat
```
```
@@ -117,7 +132,7 @@ Data/
Notes:
- `StormLib` is required to build/run the extractor (`asset_extract`), but the main client does not require StormLib at runtime.
-- `extract_assets.sh` supports `classic`, `tbc`, `wotlk` targets.
+- `extract_assets.sh` / `extract_assets.ps1` support `classic`, `tbc`, `wotlk` targets.
#### 2) Point wowee at the extracted data
@@ -184,6 +199,7 @@ make -j$(nproc)
- [Project Status](docs/status.md) -- Current code state, limitations, and near-term direction
- [Quick Start](docs/quickstart.md) -- Installation and first steps
- [Build Instructions](BUILD_INSTRUCTIONS.md) -- Detailed dependency, build, and run guide
+- [Asset Pipeline GUI](docs/asset-pipeline-gui.md) -- Python GUI for extraction, pack installs, ordering, and override rebuilds
### Technical Documentation
- [Architecture](docs/architecture.md) -- System design and module overview
@@ -206,7 +222,7 @@ make -j$(nproc)
## Technical Details
-- **Platform**: Linux (primary), C++20, CMake 3.15+
+- **Platform**: Linux (primary), Windows (MSYS2/MSVC), macOS — C++20, CMake 3.15+
- **Dependencies**: SDL2, Vulkan, GLM, OpenSSL, ImGui, FFmpeg, Unicorn Engine (StormLib for asset extraction tooling)
- **Architecture**: Modular design with clear separation (core, rendering, networking, game logic, asset pipeline, UI, audio)
- **Networking**: Non-blocking TCP, SRP6a authentication, RC4 encryption, WoW 3.3.5a protocol
diff --git a/build.sh b/build.sh
index 233be10a..f5a2d8f1 100755
--- a/build.sh
+++ b/build.sh
@@ -16,8 +16,9 @@ echo "Configuring with CMake..."
cmake .. -DCMAKE_BUILD_TYPE=Release
# Build with all cores
-echo "Building with $(nproc) cores..."
-cmake --build . --parallel $(nproc)
+NPROC=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4)
+echo "Building with $NPROC cores..."
+cmake --build . --parallel "$NPROC"
# Ensure Data symlink exists in bin directory
cd bin
diff --git a/docs/asset-pipeline-gui.md b/docs/asset-pipeline-gui.md
new file mode 100644
index 00000000..08c66711
--- /dev/null
+++ b/docs/asset-pipeline-gui.md
@@ -0,0 +1,194 @@
+# Asset Pipeline GUI
+
+WoWee includes a Python GUI for extraction and texture-pack management:
+
+```bash
+python3 tools/asset_pipeline_gui.py
+```
+
+The script is also executable directly: `./tools/asset_pipeline_gui.py`
+
+## Supported Platforms
+
+- Linux
+- macOS
+- Windows
+
+The app uses Python's built-in `tkinter` module. If `tkinter` is missing, install the platform package:
+
+- Linux (Debian/Ubuntu): `sudo apt install python3-tk`
+- Fedora: `sudo dnf install python3-tkinter`
+- Arch: `sudo pacman -S tk`
+- macOS: use the official Python.org installer (includes Tk)
+- Windows: use the official Python installer and enable Tcl/Tk support
+
+## What It Does
+
+- Runs `asset_extract` (or shell/PowerShell script fallback) to extract MPQ data
+- Saves extraction config in `asset_pipeline/state.json`
+- Installs texture packs from ZIP or folders (with zip-slip protection)
+- Lets users activate/deactivate packs and reorder active pack priority
+- Rebuilds `Data/override` from active pack order (runs in background thread)
+- Shows current data state (`manifest.json`, entry count, override file count, last runs)
+- Browses extracted assets with inline previews (images, 3D wireframes, data tables, text, hex dumps)
+
+## Configuration Tab
+
+### Path Settings
+
+| Field | Description |
+|-------|-------------|
+| **WoW Data (MPQ source)** | Path to your WoW client's `Data/` folder containing `.MPQ` files |
+| **Output Data directory** | Where extracted assets land. Defaults to `/Data` |
+| **Extractor binary/script** | Optional. Leave blank for auto-detection (see below) |
+
+### Extractor Auto-Detection
+
+When no extractor path is configured, the GUI searches in order:
+
+1. `build/bin/asset_extract` — CMake build with bin subdirectory
+2. `build/asset_extract` — CMake build without bin subdirectory
+3. `bin/asset_extract` — standalone binary
+4. **Windows only**: `extract_assets.ps1` — invoked via `powershell -ExecutionPolicy Bypass -File`
+5. **Linux/macOS only**: `extract_assets.sh` — invoked via `bash`
+
+On Windows, `.exe` is appended to binary candidates automatically.
+
+### Extraction Options
+
+| Option | Description |
+|--------|-------------|
+| **Expansion** | `auto`, `classic`, `turtle`, `tbc`, or `wotlk`. Read-only dropdown. |
+| **Locale** | `auto`, `enUS`, `enGB`, `deDE`, `frFR`, etc. Read-only dropdown. |
+| **Threads** | Worker thread count. 0 = auto (uses all cores). |
+| **Skip DBC extraction** | Skip database client files (faster if you only want textures). |
+| **Generate DBC CSV** | Output human-readable CSV alongside binary DBC files. |
+| **Verify CRC** | Check file integrity during extraction (slower but safer). |
+| **Verbose output** | More detail in the Logs tab. |
+
+### Buttons
+
+| Button | Action |
+|--------|--------|
+| **Save Configuration** | Writes all settings to `asset_pipeline/state.json`. |
+| **Run Extraction** | Starts the extractor in a background thread. Output streams to the Logs tab. |
+| **Cancel Extraction** | Terminates a running extraction. Grayed out when idle, active during extraction. |
+| **Refresh State** | Reloads the Current State tab. |
+
+## Texture Packs Tab
+
+### Installing Packs
+
+- **Install ZIP**: Opens a file picker for `.zip` archives. Each member path is validated against zip-slip attacks before extraction.
+- **Install Folder**: Opens a folder picker and copies the entire folder into the pipeline's internal pack storage.
+
+### Managing Packs
+
+| Button | Action |
+|--------|--------|
+| **Activate** | Adds the selected pack to the active override list. |
+| **Deactivate** | Removes the selected pack from the active list (stays installed). |
+| **Move Up / Move Down** | Changes priority order. Pack #1 is the base layer; higher numbers override lower. |
+| **Rebuild Override** | Merges all active packs into `Data/override/` in a background thread. UI stays responsive. |
+| **Uninstall** | Removes the pack from disk after confirmation. |
+
+Pack list selection is preserved across refreshes — you can activate a pack and immediately reorder it without re-selecting.
+
+## Pack Format
+
+Supported pack layouts:
+
+1. `PackName/Data/...`
+2. `PackName/data/...`
+3. `PackName/...` where top folders include game folders (`Interface`, `World`, `Character`, `Textures`, `Sound`)
+4. Single wrapper directory containing any of the above
+
+When multiple active packs contain the same file path, **later packs in active order win**.
+
+## Asset Browser Tab
+
+Browse and preview every extracted asset visually. Requires a completed extraction with a `manifest.json` in the output directory.
+
+### Layout
+
+- **Top bar**: Search entry, file type filter dropdown, Search/Reset buttons, result count
+- **Left panel** (~30%): Directory tree built lazily from `manifest.json`
+- **Right panel** (~70%): Preview area that adapts to the selected file type
+- **Bottom bar**: File path, size, and CRC from manifest
+
+### Search and Filtering
+
+Type a substring into the search box and/or pick a file type from the dropdown, then click **Search**. The tree repopulates with matching results (capped at 5000 entries). Click **Reset** to restore the full tree.
+
+File type filters: All, BLP, M2, WMO, DBC, ADT, Audio, Text.
+
+### Preview Types
+
+| Type | What You See |
+|------|--------------|
+| **BLP** | Converted to PNG via `blp_convert --to-png`, displayed as an image. Cached in `asset_pipeline/preview_cache/`. |
+| **M2** | Wireframe rendering of model vertices and triangles on a Canvas. Drag to rotate, scroll to zoom. |
+| **WMO** | Wireframe of group geometry (MOVT/MOVI chunks). Root WMOs auto-load the `_000` group file. |
+| **CSV** (DBC exports) | Scrollable table with column names from `dbc_layouts.json`. First 500 rows loaded, click "Load more" for the rest. |
+| **ADT** | Colored heightmap grid parsed from MCNK chunks. |
+| **Text** (XML, LUA, JSON, HTML, TOC) | Syntax-highlighted scrollable text view. |
+| **Audio** (WAV, MP3, OGG) | Metadata display — format, channels, sample rate, duration (WAV). |
+| **Other** | Hex dump of the first 512 bytes. |
+
+### Wireframe Controls
+
+- **Left-click drag**: Rotate the model (azimuth + elevation)
+- **Scroll wheel**: Zoom in/out
+- Depth coloring: closer geometry renders brighter
+
+### Optional Dependencies
+
+| Dependency | Required For | Fallback |
+|------------|-------------|----------|
+| [Pillow](https://pypi.org/project/Pillow/) (`pip install Pillow`) | BLP image preview | Shows install instructions |
+| `blp_convert` (built with project) | BLP → PNG conversion | Shows "not found" message |
+
+All other previews (wireframe, table, text, hex) work without any extra dependencies.
+
+### Cache
+
+BLP previews are cached as PNG files in `asset_pipeline/preview_cache/` keyed by path and file size. Delete this directory to clear the cache.
+
+## Current State Tab
+
+Shows a summary of pipeline state:
+
+- Output directory existence and `manifest.json` entry count
+- Override folder file count and last build timestamp
+- Installed and active pack counts with priority order
+- Last extraction time, success/failure, and the exact command used
+- Paths to the state file and packs directory
+
+Click **Refresh** to reload, or it auto-refreshes after operations.
+
+## Logs Tab
+
+All extraction output, override rebuild messages, cancellations, and errors stream here in real time via a log queue polled every 120ms. Click **Clear Logs** to reset.
+
+## State Files and Folders
+
+| Path | Description |
+|------|-------------|
+| `asset_pipeline/state.json` | All configuration, pack metadata, and extraction history |
+| `asset_pipeline/packs//` | Installed pack contents (one directory per pack) |
+| `asset_pipeline/preview_cache/` | Cached BLP → PNG conversions for the Asset Browser |
+| `