A modern browser client for Habbo retro hotels, built with React 19, TypeScript and PixiJS 8.
Octane · Octane Renderer · Polaris Emulator · Confurter · Discord
Octane is the user interface of the hotel: navigator, catalog, inventory, chat, Wired Creator Tools and everything else you click on. The rooms, avatars and furniture are drawn by its companion, the Octane Renderer. It talks to the Polaris Emulator over WebSockets.
Octane started as a fork of Nitro React and Nitro Renderer. It is developed independently and has no ties to Billsonnn / Nitro.
- React 19 + Vite 8 + TypeScript, with Zustand, TanStack Query and Vitest
- Habbo's
.habasset bundles as well as.nitro: furniture, clothes and pets, including Habbo's own.habfiles as downloaded - JSON or JSONC configuration: comments and trailing commas allowed when you want them
- Split gamedata: FurnitureData, FigureData and friends as many small files in
core/,custom/andseasonal/tiers - UI texts in 7 languages: English, Dutch, German, French, Spanish, Italian and Arabic
- One-command installer for a fresh setup, with a headless mode for CI
| Tool | Version |
|---|---|
| Git | any recent version |
| Node.js | 22.12 or newer |
| Yarn | 4 (run corepack enable once; the version is pinned in package.json) |
You also need a running Polaris Emulator and your game assets
(.nitro / .hab bundles and gamedata), which you can make with the
Confurter.
Clone Octane and run the installer from its root:
git clone https://github.com/duckietm/Octane.git
cd Octane
# Windows
install.bat
# Linux / macOS
./install.shBoth wrappers run node install.mjs, which you can also call directly. The installer:
- Checks Node, Yarn and Git
- Clones the renderer next to Octane (
../Octane-Renderer) when it is not there yet - Installs the renderer's dependencies
- Installs Octane's dependencies
- Copies
public/configuration/*.exampleto*.json(existing files are kept) - Asks for the JSON parsing mode (JSONC recommended) and saves it in
.octane-build.json - Asks for your URLs and validates them
- Asks whether to encrypt config, gamedata and
/api(secure mode), sets the two flags inclient-mode.json, and either patches the emulator'sconfig.ini(backup first) or prints the lines to paste, with a freshly generatednitro.secure.master_key - Builds the client
- Prints a summary
Re-running it is safe: existing config files are kept and only the URL keys you pass are patched. A nitro.secure.master_key that is already set in config.ini is never replaced.
Headless / CI install
Every step can be driven from flags:
node install.mjs --non-interactive \
--json-mode=jsonc \
--socket-url=wss://example.com/ws \
--api-url=https://example.com \
--asset-url=https://example.com/gamedata \
--image-library-url=https://example.com/c_images \
--hof-furni-url=https://example.com/hof_furni \
--camera-url=https://example.com/camera \
--thumbnails-url=https://example.com/thumbnails \
--habbopages-url=/habbopages \
--api-base-url=https://example.com \
--plain-config-base-url=https://example.com/configuration \
--plain-gamedata-base-url=https://example.com/gamedata--non-interactive/--skip-prompts: keep the example defaults unless a URL flag is passed--json-mode=<jsonc|legacy|auto>: pick the parser without the prompt--secure=<on|off>,--secure-api=<on|off>: secure mode without the prompt; without--securea non-interactive run leaves it as it is--emulator-config=<path to config.ini>: patch the emulator config instead of printing the values--skip-build,--skip-clone,--skip-link: skip those steps on a re-run--help: every flag, including one per URL key
Octane finds the renderer as a sibling folder, so clone both repositories into the same parent folder:
git clone https://github.com/duckietm/Octane-Renderer.git
git clone https://github.com/duckietm/Octane.git
cd Octane-Renderer && yarn install
cd ../Octane && yarn installyour-folder/
├── Octane/
└── Octane-Renderer/
Then copy the configuration examples (see below), set your URLs and build with yarn build.
All runtime configuration lives in public/configuration/. Copy each .example you need to its real name:
| File | What to set |
|---|---|
renderer-config.json |
socket.url, api.url, asset.url, image.library.url, hof.furni.url and the asset URLs below |
ui-config.json |
camera.url, thumbnails.url, url.prefix, habbopages.url |
client-mode.json |
apiBaseUrl, plainConfigBaseUrl, plainGamedataBaseUrl |
UITexts_<lang>.jsonc |
the interface texts per language |
Habbo's own client now loads every asset as a .hab bundle. Octane loads both .hab and .nitro. Which one is
used is decided by the extension in each asset URL:
- Habbo's
.habfurniture, clothes and pets work as downloaded - A URL only loads its own extension: convert custom furni, custom pets and
landscapebefore switching (the Confurter's Nitro … to HAB tools do that) - Keep Octane's own
landscapebundle: Habbo'slandscape.habis only the catalogue item - Your web server must send CORS headers for
.habjust like for.nitro
Octane can read the configuration and gamedata files in two ways:
| Mode | Behaviour |
|---|---|
jsonc (recommended) |
Comments and trailing commas are allowed; keys and strings still need double quotes |
legacy |
Strict JSON only; a comment or trailing comma stops the load with a clear error |
auto |
Strict JSON first, JSONC as a fallback |
The first yarn start or yarn build asks which mode to use and stores it in .octane-build.json (git-ignored, so
every deployment keeps its own choice). Change it later with yarn configure, or for one build only:
OCTANE_JSON_MODE=legacy yarn buildThe choice is compiled in as __OCTANE_JSON_MODE__ and used for every config and gamedata file the renderer loads.
Instead of one large file (FurnitureData.json can be tens of MB), gamedata can be a folder of small files in three tiers:
gamedata/furnidata/
├── manifest.jsonc { "tiers": ["core", "custom", "seasonal"] }
├── core/ vendor baseline
│ ├── manifest.jsonc { "files": ["floor-001.jsonc", "wall-001.jsonc"] }
│ ├── floor-001.jsonc
│ └── wall-001.jsonc
├── custom/ your additions and overrides (optional)
└── seasonal/ date-bound content such as Christmas (optional)
Tiers load in order and later files override earlier ones that share an id, classname or name. Point the
config at the folder; the trailing slash switches on split mode:
"furnidata.url": "https://example.com/gamedata/furnidata/"Create the core/ tier from an existing file with the bundled splitter:
node scripts/split-gamedata.mjs --input ./FurnitureData.json --output ./gamedata/furnidataIt detects the gamedata type (FurnitureData, FigureData, FigureMap, EffectMap, ProductData, HabboAvatarActions,
ExternalTexts / UITexts) and picks a sensible split. Run it with --help for all options. You can migrate one gamedata
file at a time; single files keep working.
| Goal | Command |
|---|---|
| Dev server with hot reload | yarn start |
Production build (dist/) |
yarn build |
| Production build with fresh browser data | yarn build:prod |
| Preview the production build | yarn preview |
| Type-check | yarn typecheck |
| Lint | yarn lint (Biome) |
| Hook-order lint | yarn lint:hooks |
| Tests | yarn test |
During development, game assets are served from a sibling Nitro-Files/ folder (/nitro-assets and /swf), so you
do not need to copy them into public/.
Run yarn build and upload the contents of dist/ to your web server, or point your CMS at it. Check your CMS
documentation for how it embeds the client.
| Project | What it does |
|---|---|
| Octane Renderer | Draws rooms, avatars and furniture (PixiJS 8) and handles the WebSocket protocol |
| Polaris Emulator | The game server |
| Confurter | Downloads Habbo's assets and converts SWF / Nitro / HAB bundles |
Questions, bugs or ideas? Join us on Discord.
Octane is licensed under the GNU General Public License v3.0.