Websites
Create in-game websites accessible through the FirebearBrowser. Websites use HTML pages rendered inside sandboxed WebViews.
Basic Website
import { Website, RegisterWebsite } from "@hotbunny/hackhub-content-sdk";
import homePage from "./pages/home.html";
import aboutPage from "./pages/about.html";
import postsPage from "./pages/posts.html";
@RegisterWebsite
export class HackerForum extends Website {
SiteName = "Hacker Forum";
Host = "hackerforum.net";
Icon = "./assets/forum-icon.png";
Pages = [
{ path: "/", title: "Home", html: homePage },
{ path: "/about", title: "About", html: aboutPage },
{ path: "/posts", title: "Posts", html: postsPage },
];
}Import HTML files directly — the build system bundles them as strings automatically.
Properties
| Property | Type | Description |
|---|---|---|
SiteName | string | Display name of the website |
Host | string | Domain name (e.g. hackerforum.net) |
Icon | string | Path to the website favicon |
Pages | (WebsitePageDefinition | DynamicWebsitePageDefinition)[] | Array of page definitions |
Popular | boolean | Show in the browser's popular sites |
Exports | Record<string, any> | Functions/values exposed to HTML |
Pages
Each page in the Pages array has:
| Property | Type | Description |
|---|---|---|
path | string | URL path (e.g. /, /about, /products/:id) |
title | string | Page title shown in the browser tab |
html | string | HTML content (import from .html file) |
seo | boolean? | If true, page appears in browser search results |
description | string? | Description shown in search results |
search | string[]? | Extra keywords for search ranking |
Example with description and search keywords:
Pages = [
{
path: "/",
title: "Hacker Forum - Home",
description: "The underground community for elite hackers.",
html: homePage,
seo: true,
search: ["hacking", "forum", "underground"],
},
{
path: "/about",
title: "About Us",
description: "Learn more about Hacker Forum.",
html: aboutPage,
seo: true,
},
];Dynamic Pages
For pages with URL parameters (e.g. /products/:id), use DynamicWebsitePageDefinition with a metadata() function instead of static title/html:
import { Website, RegisterWebsite, DynamicWebsitePageDefinition } from "@hotbunny/hackhub-content-sdk";
import productPage from "./pages/product.html";
import homePage from "./pages/home.html";
@RegisterWebsite
export class MyShop extends Website {
SiteName = "My Shop";
Host = "myshop.mod";
Icon = "";
Pages = [
{ path: "/", title: "My Shop", html: homePage, seo: true },
{
path: "/products/:productId",
seo: true,
metadata(context) {
const products: Record<string, { name: string; desc: string }> = {
"1": { name: "VPN Pro", desc: "Anonymous browsing tool" },
"2": { name: "CrackKit", desc: "Password recovery suite" },
};
const product = products[context.params.productId];
if (!product) return null; // 404
return {
title: `${product.name} - My Shop`,
description: product.desc,
html: productPage,
search: [product.name.toLowerCase()],
exports: { product },
};
},
} satisfies DynamicWebsitePageDefinition,
];
}PageContext
The metadata() function receives a context object:
| Property | Type | Description |
|---|---|---|
url | string | Full URL being navigated to |
params | Record<string, string> | Route parameters (:productId → "1") |
query | Record<string, string> | Query string parameters (?sort=price) |
searchStr | string? | Search query (when called from Goagle search) |
PageMetadata
Return an object describing the page, or null to show a 404:
| Property | Type | Description |
|---|---|---|
title | string | Page title |
description | string? | Search result description |
html | string | HTML content to render |
search | string[]? | Dynamic search keywords |
exports | Record<string, any>? | Values exposed as globals in the HTML |
HTML Pages
Your HTML files are rendered inside sandboxed WebViews. You have full control over the page content:
<!DOCTYPE html>
<html>
<head>
<style>
body { background: #1a1a2e; color: #eee; font-family: monospace; }
h1 { color: #0f0; }
</style>
</head>
<body>
<h1>Welcome to Hacker Forum</h1>
<p>The underground community for elite hackers.</p>
</body>
</html>Exports
Expose TypeScript functions and values to your HTML pages:
@RegisterWebsite
class MyWebsite extends Website {
SiteName = "My Site";
Host = "mysite.com";
Icon = "./assets/icon.png";
Pages = [
{ path: "/", title: "Home", html: homePage },
];
Exports = {
formatPost: (text: string) => text.toUpperCase(),
siteVersion: "1.0.0",
};
}In your HTML, exported values are available as globals:
<script>
const formatted = formatPost("hello world");
document.getElementById("version").textContent = siteVersion;
</script>Page Navigation
Links between your website's pages work automatically. Use standard <a> tags with relative or absolute URLs:
<a href="/about">About Us</a>
<a href="https://hackerforum.net/posts">Posts</a>Clicking a link will navigate the in-game browser to the correct page — no extra code needed.
For programmatic navigation, use the HackhubSDK.Browser API:
<script>
// Navigate to a page on your site
HackhubSDK.Browser.navigate("https://hackerforum.net/about");
// Navigate to any website in the game
HackhubSDK.Browser.navigate("https://goagle.com");
</script>| Method | Description |
|---|---|
Browser.navigate(url) | Navigate the browser to the given URL |
Browser.push(url) | Push a new URL to the browser history |
SDK Access in HTML
All SDK APIs are available via the HackhubSDK global (Context Bridge):
<script>
HackhubSDK.Mail.send({
from: "[email protected]",
subject: "Welcome",
content: "Thanks for registering!",
});
HackhubSDK.Events.emit("MyMod.UserRegistered", { username: "hacker" });
</script>See the WebView Context Bridge reference for the full list of available APIs.
