# How the Alternate Assets System in Lighthouse Works: Tab Key Toggle Explained

> Explore Lighthouse's alternate assets system. Instantly toggle custom graphics with the Tab key. Learn how this resource redirection feature enhances your game.

- Repository: [Harbour Masters/Lighthouse](https://github.com/HarbourMasters/Lighthouse)
- Tags: deep-dive
- Published: 2026-08-04

---

**The alternate assets system in Lighthouse is a resource redirection feature that lets mods replace original game graphics with high-resolution or custom assets, which players can toggle on and off instantly using the Tab key when the "Mods Tab Hotkey" option is enabled.**

Lighthouse, the open-source engine powering modern ports of classic Nintendo 64 games, includes a sophisticated **alternate assets system** designed to support HD texture packs and custom mod content. This system allows the game to dynamically switch between original ROM-baked graphics and higher-quality replacements stored in external files. The entire workflow centers on a global flag called `Mods.AlternateAssets`, which users can flip on demand with a single keystroke.

## Core Architecture: Resource Manager and Event Listeners

The alternate assets implementation lives in the **resource manager's Alt module**, specifically in [`src/port/Resource/Alt/AltSprites.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/src/port/Resource/Alt/AltSprites.cpp). When the engine prepares to load any sprite, it fires the `ResolveSpriteHdPath` event. The listener registered in [`AltSprites.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/AltSprites.cpp) intercepts this event and performs a critical check:

```cpp
// AltSprites.cpp – core redirection logic (lines 69-71)
if (!Ship::Context::GetRawInstance()->GetResourceManager()->IsAltAssetsEnabled()) {
    return nullptr;          // fall back to the built-in texture
}

```

If `IsAltAssetsEnabled()` returns **false**, the listener yields control and the original texture loads normally. If **true**, the listener returns a specially formatted path beginning with `__OTR__` that points to the corresponding file under the `alt/` directory. The same pattern applies to fonts via [`AltBoldFont.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/AltBoldFont.cpp) and other resource types that expose resolution events.

## The Tab Key Toggle: CVar-Based Control Flow

User control over this system flows through **two interdependent console variables (CVars)**:

| CVar | Purpose | Default |
|------|---------|---------|
| `Mods.AlternateAssets` | Master flag enabling/disabling alternate asset loading | `false` |
| `Mods.AlternateAssetsHotkey` | Enables Tab key as a toggle shortcut | `true` |

The UI layer defines these controls in [`src/port/UI/LighthouseModMenuWindow.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/src/port/UI/LighthouseModMenuWindow.cpp):

```cpp
// LighthouseModMenuWindow.cpp – hotkey widget definition (lines 95-103)
tabHotkeyWidget = { .name = "Mods Tab Hotkey", .type = WidgetType::WIDGET_CVAR_CHECKBOX };
tabHotkeyWidget.CVar(CVAR_SETTING("Mods.AlternateAssetsHotkey"))
    .Options(UIWidgets::CheckboxOptions()
        .Tooltip("Allows pressing the Tab key to toggle mods")
        .DefaultValue(true));
LighthouseGui::mLighthouseMenu->AddSearchWidget(
    { tabHotkeyWidget, "Settings", "Mod Menu", "Top", "alternate assets tab hotkey" });

```

When `Mods.AlternateAssetsHotkey` is enabled, the UI framework intercepts Tab key presses and automatically inverts the `Mods.AlternateAssets` boolean. This toggle triggers `SaveConsoleVariablesNextFrame`, ensuring persistence without blocking the current frame.

## What Happens When You Press Tab

The complete toggle sequence operates as follows:

1. **Input detection**: The UI layer receives the Tab key press event.
2. **Permission check**: The system verifies `Mods.AlternateAssetsHotkey` is `true`.
3. **State inversion**: The current value of `Mods.AlternateAssets` is read and flipped (`true` becomes `false`, or vice versa).
4. **Persistence**: The new value is written back to the CVar and queued for save.
5. **Immediate effect**: On the next resource load, `IsAltAssetsEnabled()` reflects the updated state, causing all subsequent sprite and font resolutions to switch between `alt/` directory assets and original inline data.

This architecture means **no engine restart is required**—the change applies instantly to all new texture loads.

## How Mods Register Alternate Assets

Mods integrated with Lighthouse hook into this system by registering chunk-to-path mappings during initialization. The registration API is exposed as:

```cpp
// Example registration from a mod's init code
extern "C" void port_spriteAltRegisterChunk(const void* chunkAddr, const char* path);
port_spriteAltRegisterChunk(myChunkPtr, "__OTR__/my_mod/alt_texture.png");

```

The `port_spriteAltRegisterChunk` function stores the mapping in `sChunkPaths`. When `ResolveSpriteHdPath` fires, the listener looks up the original chunk address; if found and alternate assets are enabled, it returns the registered replacement path. This mechanism works uniformly across **sprites, fonts, and any resource implementing resolution events**.

## Practical Code Examples

### Manual toggle via console command

```cpp
// Flip the alternate assets flag programmatically
CVarSetBool(CVAR_SETTING("Mods.AlternateAssets"), !CVarGetBool(CVAR_SETTING("Mods.AlternateAssets")));

```

### Register a custom sprite replacement

```cpp
// Inside your mod's ShipInit callback
extern "C" void port_spriteAltRegisterChunk(const void* chunkAddr, const char* path);
port_spriteAltRegisterChunk(gShipTextureOriginal, "__OTR__/my_hd_pack/ship_diffuse.png");

```

### Implement custom Tab hotkey handling

```cpp
// Optional: Raw key detection for custom UI elements
if (UI::IsKeyPressed(ImGuiKey_Tab) && CVarGetBool(CVAR_SETTING("Mods.AlternateAssetsHotkey"))) {
    CVarSetBool(CVAR_SETTING("Mods.AlternateAssets"),
                !CVarGetBool(CVAR_SETTING("Mods.AlternateAssets")));
}

```

## Key Implementation Files

Understanding the full scope of this feature requires familiarity with these source files:

- **[`src/port/UI/LighthouseModMenuWindow.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/src/port/UI/LighthouseModMenuWindow.cpp)** — Defines the checkbox widgets for `Mods.AlternateAssets` and `Mods.AlternateAssetsHotkey`; handles UI integration and search indexing.
- **[`src/port/Resource/Alt/AltSprites.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/src/port/Resource/Alt/AltSprites.cpp)** — Core event listener implementing the `ResolveSpriteHdPath` redirection logic.
- **[`src/port/Resource/Alt/AltBoldFont.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/src/port/Resource/Alt/AltBoldFont.cpp)** — Parallel implementation for bold font textures, following identical patterns.
- **[`src/port/ShipInit.hpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/src/port/ShipInit.hpp)** — Registers the AltSprites initialization function with Lighthouse's module loader.

## Summary

- The **alternate assets system** enables runtime substitution of original graphics with HD or mod-provided replacements.
- State is controlled by the `Mods.AlternateAssets` CVar, checked via `ResourceManager::IsAltAssetsEnabled()` in [`AltSprites.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/AltSprites.cpp).
- The **Tab key toggle** is optional and governed by `Mods.AlternateAssetsHotkey`; when enabled, it inverts the master flag instantly.
- Mods register replacements using `port_spriteAltRegisterChunk()`, mapping original chunk addresses to `__OTR__` paths in the `alt/` directory.
- The implementation is fully event-driven, requiring no engine restarts and applying changes on the next resource load.

## Frequently Asked Questions

### Where is the alternate assets toggle located in Lighthouse's menus?

The toggle appears in **Settings → Mod Menu** as two related options: a master "Alternate Assets" checkbox and a "Mods Tab Hotkey" checkbox that enables the Tab key shortcut. Both are defined in [`LighthouseModMenuWindow.cpp`](https://github.com/HarbourMasters/Lighthouse/blob/main/LighthouseModMenuWindow.cpp) and indexed for the menu search system.

### Why does my texture pack not appear immediately after pressing Tab?

Alternate assets only affect **subsequent** resource loads. Textures already cached in GPU memory will not refresh until the scene changes or the cache invalidates. For immediate visual updates, some users trigger a room transition or use developer commands to force asset reloads.

### Can I disable the Tab hotkey if it conflicts with other controls?

Yes. Set `Mods.AlternateAssetsHotkey` to `false` either through the Mod Menu UI or directly via CVar command. This leaves the alternate assets system functional but removes the keyboard shortcut, requiring manual toggling through the menu or console.

### What file path format do alternate assets use?

Lighthouse uses **OTR-style virtual paths** prefixed with `__OTR__/`. These resolve to physical files under the `alt/` subdirectory of your game or mod folder. For example, `__OTR__/my_pack/texture.png` maps to `alt/my_pack/texture.png` on disk.