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

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. When the engine prepares to load any sprite, it fires the ResolveSpriteHdPath event. The listener registered in AltSprites.cpp intercepts this event and performs a critical check:

// 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 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:

// 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:

// 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

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

Register a custom sprite replacement

// 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

// 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:

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.
  • 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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →