Overview & Architecture
A games hub is the most common type of UBG site. The core idea is simple: you present a curated list of games, and when a user clicks one, it loads inside an iframe or a dedicated game page — bypassing school/work network filters by either using a proxy or loading from a CDN source that isn't blocked.
There are two fundamental approaches: CDN embedding (link to games hosted elsewhere — fast to ship, zero storage cost) and self-hosting (download and serve games yourself — more reliable, no third-party downtime). Most professional sites combine both.
The typical file structure for a games site looks like this:
my-games-site/ ├── index.html # Home / game grid ├── game.html # Game viewer page (fullscreen iframe) ├── assets/ │ ├── style.css │ └── main.js ├── data/ │ └── games.json # All game metadata └── games/ # Self-hosted games (optional) ├── slope/ └── 1v1-lol/
Game Embed Methods
Pick the right embedding strategy for each game. Most sites use a mix depending on what's available for a given title.
Direct iframe
Load a CDN URL directly inside an <iframe>. The simplest approach — no backend required. Works when the source allows cross-origin framing.
Self-hosted ZIP
Download the game's HTML5 bundle, unzip it into your repo, and serve it as a static folder. 100% reliable — no external dependency.
Most ReliableProxy iframe
Pass the game URL through your Ultraviolet/Scramjet proxy. Useful for games on domains that block direct iframes.
AdvancedGitHub Raw / jsDelivr
Host game files in a GitHub repo and serve them via cdn.jsdelivr.net. Free, fast CDN without a dedicated server.
X-Frame-Options: DENY or Content-Security-Policy: frame-ancestors 'none', which will block your iframe. You can't override this without a proxy — fall back to the proxy or self-hosted method for these titles.
Basic iframe Setup
The game viewer page should be a fullscreen iframe with a minimal chrome overlay for navigation. Here's the standard pattern:
<!-- game.html — fullscreen game viewer --> <!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width,initial-scale=1"> <style> * { margin:0; padding:0; box-sizing:border-box; } body { background:#000; height:100vh; overflow:hidden; } #game-frame { position: fixed; inset: 0; width: 100%; height: 100%; border: none; } /* Minimal top bar */ #bar { position: fixed; top: 0; left: 0; right: 0; height: 40px; background: rgba(0,0,0,0.7); backdrop-filter: blur(8px); display: flex; align-items: center; gap: 10px; padding: 0 14px; z-index: 999; transform: translateY(-40px); transition: transform 0.25s ease; } body:hover #bar { transform: translateY(0); } #game-title { color: #fff; font-size: 0.82rem; font-family: sans-serif; flex: 1; } .bar-btn { color: rgba(255,255,255,0.7); background: none; border: 1px solid rgba(255,255,255,0.15); border-radius: 6px; padding: 4px 10px; font-size: 0.75rem; cursor: pointer; transition: background 0.15s; } .bar-btn:hover { background: rgba(255,255,255,0.1); } </style> </head> <body> <div id="bar"> <span id="game-title"></span> <button class="bar-btn" onclick="toggleFullscreen()">⛶ Fullscreen</button> <a href="index.html" class="bar-btn">← Back</a> </div> <iframe id="game-frame" allowfullscreen sandbox="allow-scripts allow-same-origin allow-pointer-lock allow-forms" ></iframe> <script> const params = new URLSearchParams(location.search); const src = params.get('src'); const title = params.get('title') || 'Game'; document.getElementById('game-frame').src = src; document.getElementById('game-title').textContent = title; document.title = title; function toggleFullscreen() { const frame = document.getElementById('game-frame'); if (!document.fullscreenElement) { frame.requestFullscreen(); } else { document.exitFullscreen(); } } </script> </body> </html>
Link to this page from your game grid by passing the source URL as a query parameter:
<a href="game.html?src=https://games.cdn.example/slope/index.html&title=Slope"> Play Slope </a>
sandbox attribute on game iframes. The combination above covers 99% of HTML5 games — it allows scripts, pointer lock (needed for FPS-style games), and form submissions, while still providing a security boundary.
Building a Game Library
Store all game metadata in a games.json file and render cards dynamically. This is far easier to maintain than hardcoded HTML.
[
{
"id": "slope",
"title": "Slope",
"description": "Dodge obstacles as your ball speeds down an endless slope.",
"thumbnail": "assets/thumbs/slope.webp",
"src": "https://your-cdn.example/slope/index.html",
"categories": ["arcade", "popular"],
"featured": true
},
{
"id": "1v1-lol",
"title": "1v1.LOL",
"description": "Build, battle, and outplay your opponents.",
"thumbnail": "assets/thumbs/1v1lol.webp",
"src": "https://your-cdn.example/1v1lol/index.html",
"categories": ["shooter", "popular"],
"featured": false
}
]Then render the grid from JavaScript:
let allGames = []; let activeCategory = 'all'; // Fetch game data and render async function init() { const res = await fetch('data/games.json'); allGames = await res.json(); renderGrid(allGames); buildCategoryTabs(allGames); } function renderGrid(games) { const grid = document.getElementById('game-grid'); grid.innerHTML = games.map(g => ` <a class="game-card" href="game.html?src=${encodeURIComponent(g.src)}&title=${encodeURIComponent(g.title)}"> <img src="${g.thumbnail}" alt="${g.title}" loading="lazy"> <div class="game-info"> <h3>${g.title}</h3> <p>${g.description}</p> <div class="game-cats"> ${g.categories.map(c => `<span class="chip">${c}</span>`).join('')} </div> </div> </a> `).join(''); } function filterByCategory(cat) { activeCategory = cat; const filtered = cat === 'all' ? allGames : allGames.filter(g => g.categories.includes(cat)); renderGrid(filtered); } function filterBySearch(query) { const q = query.toLowerCase(); const filtered = allGames.filter(g => g.title.toLowerCase().includes(q) || g.description.toLowerCase().includes(q) ); renderGrid(filtered); } function buildCategoryTabs(games) { const cats = ['all', ...new Set(games.flatMap(g => g.categories))]; const bar = document.getElementById('cat-bar'); bar.innerHTML = cats.map(c => ` <button class="cat-btn" onclick="filterByCategory('${c}')">${c}</button> `).join(''); } init();
Game Source: GitHub + jsDelivr
The recommended way to host your own game files is to commit them to a GitHub repository and serve them through jsDelivr — a free, globally distributed CDN that mirrors GitHub content. You get a fast, reliable URL for every file with zero server costs and no extra configuration.
The URL pattern is straightforward:
# Pattern https://cdn.jsdelivr.net/gh/{user}/{repo}@{branch}/{path/to/file} # Example — serve slope's index.html from a repo called "game-files" https://cdn.jsdelivr.net/gh/yourname/game-files@main/slope/index.html
Here's the complete workflow from repo setup to a working game URL:
Create a public GitHub repo for game files
Make a new repo (e.g. game-files) and set it to public — jsDelivr only mirrors public repositories. You can keep your main site repo private and have a separate public repo just for game assets.
Add game folders and commit
Each game lives in its own folder: slope/index.html, slope/game.js, etc. Commit all files to the main branch. jsDelivr will cache them within minutes of the push.
Reference the jsDelivr URL in games.json
Point each game's "src" field to the CDN URL. Use @main to always serve the latest commit, or pin a specific commit hash for stability.
Purge the cache after updates
If you update a game file, jsDelivr may serve a stale version for up to 24 hours. Force an instant purge at https://www.jsdelivr.com/tools/purge by entering the file URL.
LuminSDK — 1,000+ Games Instantly
LuminSDK is the fastest way to add a complete, fully-featured game library to any site. One script tag, one function call, and you get 1,000+ browser games with built-in search, categories, and a fullscreen player — no accounts, no API keys, no build tools required.
The complete integration is just three lines of HTML:
<!-- 1. A container div where the game grid will render --> <div id="games"></div> <!-- 2. Load the SDK from jsDelivr --> <script src="https://cdn.jsdelivr.net/gh/luminsdk/script@latest/lumin.min.js"></script> <!-- 3. Initialize with your container and preferred theme --> <script> Lumin.init({ container: '#games', theme: 'dark' }); </script>
That's it. LuminSDK renders the entire game grid — thumbnails, search bar, category tabs, and a fullscreen player — directly into your #games div. No games.json to maintain, no iframe wiring to write.
The theme option accepts 'dark' or 'light' and matches automatically to your site's color scheme. Additional configuration options are available via Lumin.init():
Lumin.init({ container: '#games', // CSS selector or DOM element theme: 'dark', // 'dark' | 'light' // See full options at docs.luminsdk.com/configuration });
LuminSDK also exposes a JavaScript API for deeper integration — search, loading specific games programmatically, and fetching game metadata. See the Methods reference in the LuminSDK docs for the full API.
Zero to live in 2 minutes
No build step, no accounts, no API keys. Copy the three lines above, paste into your page, and you have 1,000+ games immediately.
Easiest MethodSearch & categories included
The SDK ships with a fully functional search bar and category filter system — you don't need to build any of the UI from section 07.
Batteries IncludedWorks with any stack
Plain HTML, React, Vue, Svelte — LuminSDK is a vanilla JS library with no dependencies. Drop it in anywhere.
Framework AgnosticServed via jsDelivr
The SDK script itself is hosted at cdn.jsdelivr.net/gh/luminsdk/script@latest/lumin.min.js — the same CDN used for your game files in section 05.
games.json library using sections 04–05. Both approaches can coexist on the same site — e.g. LuminSDK for the main grid, a custom-curated section for featured titles.
Self-Hosting Games
Self-hosting gives you full control — games load even if the original CDN goes down. The workflow is:
Obtain the game bundle
Download the HTML5 build from the developer's itch.io page, GitHub releases, or an open-source repository. You're looking for a folder containing an index.html and associated JS/asset files.
Place it in your games/ folder
Add the folder to your repo. Keep names lowercase with hyphens — e.g. games/cookie-clicker/. Commit the entire folder including assets.
Update games.json
Point the "src" field to the relative path: "src": "games/cookie-clicker/index.html". The viewer page will load it in the iframe just like any other URL.
Test locally and deploy
Run a local server (npx serve .) to verify the game loads correctly, then push to Cloudflare Pages or your host of choice. The Deploy guide covers this in detail.
# Requires Node.js — serves the current directory on port 3000 npx serve . -p 3000
UI & Category Filtering
A polished game grid with search and category filters dramatically improves the user experience. Here's a minimal but complete implementation:
<!-- Search bar --> <input type="text" id="search" placeholder="Search games..." oninput="filterBySearch(this.value)"> <!-- Category tabs (built dynamically from games.json) --> <div id="cat-bar"></div> <!-- Game grid --> <div id="game-grid" class="game-grid"></div>
.game-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 16px; } .game-card { border-radius: 14px; overflow: hidden; text-decoration: none; color: inherit; background: var(--glass); border: 1.5px solid var(--glass-border); transition: transform 0.22s, box-shadow 0.22s; } .game-card:hover { transform: translateY(-5px) scale(1.02); box-shadow: 0 16px 40px rgba(0,0,0,0.15); } .game-card img { width: 100%; aspect-ratio: 16/9; object-fit: cover; display: block; } .game-info { padding: 12px 14px 14px; } .game-info h3 { font-size: 0.9rem; font-weight: 600; margin-bottom: 4px; } .game-info p { font-size: 0.75rem; opacity: 0.65; line-height: 1.5; }
.webp for best performance. You can screenshot any game at that resolution or find official artwork in the game's itch.io or GitHub page assets. Use the loading="lazy" attribute on all thumbnail images so they don't slow your initial page load.
Next Steps
You now have a fully functional games hub. Here's where to go from here:
Add an AI chatbot
Drop a free LLaMA or GPT integration into your site. The AI guide covers the full setup — no API cost to your users.
AI GuideAdd background music
Let users play music while they game. The Music guide shows how to integrate a player with zero server cost.
Music GuideDeploy to Cloudflare
Push your site live with DDoS protection, CDN caching, and analytics all set up in under 15 minutes.
Deploy GuideAdd a proxy tab
Extend your games hub with a full web proxy so users can browse the open web — the highest-traffic feature of any UBG site.
Proxy Guide