Skip to content

Building & Installing Mods ​

This guide covers the full build pipeline: compiling your mod, understanding the output structure, installing it locally, and using development workflows.

Build Command ​

bash
npm run build

This compiles your mod into a ready-to-use package inside the dist/ folder. The build automatically:

  • Bundles your TypeScript into a single mod.js
  • Copies manifest.json and assets into dist/
  • Detects and includes any referenced images, audio, fonts, and other files

Customizing the Build ​

Your esbuild.config.ts can optionally override defaults:

typescript
import { buildMod } from "@hotbunny/hackhub-content-sdk/build";

buildMod({
    entryPoint: "src/index.ts",   // default
    outfile: "dist/mod.js",       // default
});

Most projects don't need to change anything here.

Output Structure ​

After a successful build, dist/ contains:

dist/
├── mod.js              # Bundled mod code
├── manifest.json       # Copied from project root
├── cover.png           # Cover image (if present in root)
├── icon.png            # Icon (if present in root)
├── settings.html       # HTML files from src/ (if any)
└── (other assets)      # Images, audio, CSS from public/ and src/

Asset Pipeline ​

Assets are collected from three sources:

1. public/ Directory ​

Everything in public/ is copied directly into dist/. Use this for static assets that aren't referenced in code:

public/
├── images/
│   └── logo.png
├── sounds/
│   └── alert.mp3
└── styles/
    └── app.css

2. Source-referenced Assets ​

Assets referenced in .ts/.tsx files with relative paths are automatically detected and copied:

typescript
// These asset references are auto-detected during build
const icon = "./assets/icon.png";
const sound = "./sfx/click.mp3";

3. Root-level Assets ​

Files in the project root matching asset extensions (.png, .jpg, .mp3, .css, etc.) are copied to dist/. This is primarily for cover.png and icon.png.

mod-asset:// Protocol ​

At runtime, mods reference their assets using the mod-asset:// protocol:

mod-asset://{mod-id}/images/logo.png

In WebView-based content (Apps, Websites), relative paths are resolved automatically:

html
<!-- Inside an App WebView, this resolves to mod-asset://my-mod/images/bg.png -->
<img src="images/bg.png" />

In script code, use the SDK's asset utilities or construct the URL manually:

typescript
const coverUrl = `mod-asset://${manifest.id}/cover.png`;

Watch Mode (Development) ​

For rapid iteration, use watch mode:

bash
npm run dev

When you save a file, the mod is automatically rebuilt. To see the rebuilt mod in game, either type reloadmods in the developer console (F1) or turn on mod dev mode below.

Mod Dev Mode (auto reload) ​

Start the game with the --mod-dev launch option (Steam → Right-click HackHub → Properties → Launch Options). In this mode the game watches the local mods/ folder and, whenever a mod's build output changes, it saves, reloads your mods and drops you back into the save you were playing. You do not go through the main menu.

The easiest setup is to keep the whole mod project inside the game's mods folder, so npm run dev writes straight to where the game reads from:

HackHub/mods/my-awesome-mod/
├── src/
├── manifest.json
├── package.json
└── dist/            # written by npm run dev, watched by the game
    ├── mod.js
    └── manifest.json

Only dist/, a root mod.js and a root manifest.json trigger a reload, so editing files in src/ does not reload the game until the build has finished. Workshop items are never watched, and mods do not run in multiplayer, so there is nothing to reload there.

reloadmods works without the launch option too. It does the same save, reload and resume in one step.

Finding Where an Error Came From ​

Errors thrown by mod code point at the mod and at the line in its mod.js, for example:

Cannot read properties of undefined (reading 'length') (my-awesome-mod/mod.js:120:17)

You see this in the Mods menu when a mod fails to load, in the terminal when a mod command throws, and on the crash screen when a mod's UI crashes. In mod dev mode, uncaught errors from your mod also pop up in game. Open dist/mod.js at that line to find the failing code.

Installing Your Mod Locally ​

To test your mod in-game, copy the dist/ contents to the game's mods/ folder:

Step by Step ​

  1. Build your mod: npm run build

  2. Locate your game's mods/ directory:

    • Steam: <Steam Library>/steamapps/common/HackHub/mods/
    • Or find it via Steam → Right-click HackHub → Manage → Browse local files → mods/

    Platform paths

    • Windows: mods/ is next to Hackhub.exe (e.g. C:\...\HackHub\mods\)
    • macOS: mods/ is next to Hackhub.app, not inside the app bundle (e.g. .../HackHub/mods/)
    • Linux: mods/ is next to the AppImage or executable
  3. Create a folder named after your mod's id: mods/{mod-id}/

  4. Copy everything from dist/ into that folder

HackHub/
├── Hackhub.exe (Windows) or Hackhub.app (macOS)
└── mods/
    └── my-awesome-mod/       # Must match manifest.json "id"
        ├── mod.js
        ├── manifest.json
        ├── cover.png
        └── ...
  1. Launch (or restart) the game, or run reloadmods in the developer console
  2. Open the Mods menu - your mod should appear in the list

Local Mod Priority ​

If a local mod and a Workshop mod share the same id, the local mod takes priority. The Workshop version is ignored as long as the local copy exists. This lets you:

  • Test changes before publishing to Workshop
  • Override Workshop mods with custom versions
  • Develop against a published mod without affecting subscribers

Troubleshooting ​

Common Build Errors ​

ErrorCauseFix
Cannot resolve "@hotbunny/hackhub-content-sdk"SDK not installedRun npm install
manifest.json not foundMissing manifestCreate manifest.json in project root
experimentalDecorators warningIncorrect tsconfigBuild auto-fixes this; re-run build
Could not resolve "./foo.html"Missing HTML fileEnsure the file exists at the referenced path

Mod Not Appearing In-Game ​

  1. Verify the folder name in mods/ matches the id field in manifest.json
  2. Check that manifest.json exists inside the mod folder (not nested deeper)
  3. Ensure mod.js (the entry field) is present
  4. Check the game's developer console for error messages

Assets Not Loading ​

  1. Confirm assets are in dist/ after building
  2. For WebView content (Apps, Websites), use relative paths - they resolve automatically
  3. For script code, use the full mod-asset://{id}/path URL
  4. Ensure asset file names match exactly (case-sensitive)

HotBunny Interactive Entertainment Inc.