1// ââ Theme Utilities ââââââââââââââââââââââââââââââââââââââââââ 2const html = document.documentElement; 3const SUN = '<svg class="icon" aria-hidden="true"><use href="#icon-sun"/></svg>'; 4const MOON = '<svg class="icon" aria-hidden="true"><use href="#icon-moon"/></svg>'; 5 6function initTheme() { 7 const themeBtn = document.getElementById('themeToggle'); 8 if (!themeBtn) return; 9 const savedTheme = localStorage.getItem('theme') || 'light'; 10 html.setAttribute('data-theme', savedTheme); 11 themeBtn.innerHTML = savedTheme === 'dark' ? SUN : MOON; 12 13 themeBtn.addEventListener('click', toggleTheme); 14} 15 16function toggleTheme() { 17 const t = html.getAttribute('data-theme') === 'dark' ? 'light' : 'dark'; 18 html.setAttribute('data-theme', t); 19 localStorage.setItem('theme', t); 20 const btn = document.getElementById('themeToggle'); 21 if (btn) btn.innerHTML = t === 'dark' ? SUN : MOON; 22 // Re-render chart if available 23 if (window.waitForChart && window.renderChart) { 24 window.waitForChart().then(window.renderChart).catch(() => {}); 25 } 26} 27 28// ââ String & Format Utilities ââââââââââââââââââââââââââââââââ 29function cap(s) { 30 return s.charAt(0).toUpperCase() + s.slice(1); 31} 32 33function fmtTime(s) { 34 return String(Math.floor(s / 60)).padStart(2, '0') + ':' + String(s % 60).padStart(2, '0'); 35} 36 37// ââ Constants âââââââââââââââââââââââââââââââââââââââââââââââââ 38const _isLocal = location.hostname === 'localhost' || location.hostname === '127.0.0.1'; 39// ?cdn=PORT loads every game from http://localhost:PORT (scripts/serve-local-games.js). 40// Remembered for the tab, because grid cards link to /games/{slug}.html without it. 41// Local hosts only: the live site never reads it. 42const _localPort = _isLocal ? (() => { 43 const q = new URLSearchParams(location.search).get('cdn'); 44 try { 45 if (q) sessionStorage.setItem('ubg_cdn', q); 46 return q || sessionStorage.getItem('ubg_cdn'); 47 } catch (e) { return q; } 48})() : null; 49 50// ââ Game shards âââââââââââââââââââââââââââââââââââââââââââââââ 51// Game files live in separate "shard" repos under the same GitHub account. A 52// project repo named `X` is served by GitHub Pages at ubghyper.github.io/X/, 53// so every shard sits on the same origin and a game folder resolves to 54// https://ubghyper.github.io/{shard}/{slug}/ 55// A game names its shard with an optional `shard` field in games.json; entries 56// without one live in the original GameList.github.io shard. Adding a new shard 57// therefore requires no code change â only the field on the new games. 58const SHARD_ORIGIN = 'https://ubghyper.github.io'; 59const SHARD_DEFAULT = 'GameList.github.io'; 60 61// ââ GENERATED by scripts/gen-play-shell.js â do not edit by hand ââââââââââââââ 62// Shard repo -> its pinned jsDelivr mirror. Thumbnails resolve through here 63// rather than github.io: on any non-github.io host, github.io is blocked by most 64// school filters, so thumbnails served from it render as a grid of empty boxes. 65const SHARD_CDN = { 66 "GameList.github.io": "https://cdn.jsdelivr.net/gh/UBGHyper/GameList.github.io@422a72130124f24fc1ef366ef3307e1ad2671ad4", 67 "gamelist2.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist2.github.io@408d7c4e1177fe8926c754144ad3b2a50ba340fb", 68 "gamelist3.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist3.github.io@985669be9312518503ffd8d19816f16a9c98120f", 69 "gamelist4.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist4.github.io@16488774e354c4ba5dcd1759fe85f1b3b20a42ff", 70 "gamelist5.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist5.github.io@1c5c32f73d8e0d0198a4890a90087537b9cc8c42", 71 "gamelist6.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist6.github.io@9055fb30d4da4715e618263a5cf225b1937e8a42", 72 "gamelist7.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist7.github.io@f49b5c32c35ee48ab179ec5a719d95ec7f
720a6d19", 73 "gamelist8.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist8.github.io@7e098d51d78090f262a5d2b4ddee3a062b2f95cf", 74 "gamelist9.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist9.github.io@0ee4fe7925333a3dff0b4d9dcefe7c534002d656", 75 "gamelist10.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist10.github.io@d5fea0594796d79bcba69576156b82e2d22ab2d1", 76 "gamelist11.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist11.github.io@6d18f59c8ece07d60618ca35e18de93943326a94", 77 "gamelist12.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist12.github.io@425bcd1a664b8f9d63fd5ef6f155a1c178b9b4a4", 78 "gamelist13.github.io": "https://cdn.jsdelivr.net/gh/freeonlinewebtools/gamelist13.github.io@deaaef4b48f030554c652fd52c3b9d79d4602aee" 79}; 80// Games that actually have a shell at /g/{slug}/. Built from what was written, 81// not from manifest eligibility â 8 games are eligible yet skipped (no entry 82// html, oversized entry) and listing those would point the iframe at nothing. 83const PLAY_SHELLS = new Set(["2048","3D-Bowling","8-Ball-Billiards-Classic","A-Dance-of-Fire-and-Ice","A-Game-About-Feeding-A-Black-Hole","ABaF","Achievement-Unlocked","Achievement-Unlocked-2","Achievement-Unlocked-3","Adventure","Adventure-Drivers","Age-Of-War","Age-Of-War-2","Alien-Hominid","Amanda-The-Adventurer","Angry-Birds-2","Anton-Blast-Demo-v12","Apes-vs-Helium","Archery-World-Tour","AttackHole","Awesome-Cars","Awesome-Planes","Awesome-Tanks","Awesome-Tanks-2","BALDI","BART-BLAST-INDEV-VERSION","BASEBALL-BROS","BERGENTRUCK-201X","BTD-4","Bacon-May-Die","Bad-Ice-Cream","Bad-Ice-Cream-2","Bad-Ice-Cream-3","Bad-Time-Simulator-Sans-Fight","Baldis-Basics-The-Ultra-Decompile","Ball-Blast-HTML5","Bartender-The-Right-Mix","Basket-Bros","Basket-Champs","Basketball-FRVR","Basketball-Legends-2020","Basketball-Line","Basketball-Stars","Bejeweled","Bendy","Big-Tower-Tiny-Square-2","Billards","Bit-Planes","Bitlife","Blackjack","Blade-Ball","Bloons-TD-5","Bloons-Tower-Defence","Bloons-Tower-Defence-2","Bloons-Tower-Defence-3","Bloxorz","Bob-The-Robber","Bobs-Onslaught","Bomb-Pass","Bottle-Jump-3D","Bouncemasters","Boxhead","Boxing-Random","Brawl-Stars","BreakLock","Breaking-The-Bank","Bubble-Tanks-Arena","Bubble-Tanks-TD-1","Bubble-Tanks-TD-2","Buckshot-Roulete","Burrito-Bison","Burrito-Bison-Revenge","Buster-Jam","CSGO","Cactus-McCoy-2","Canabalt","Candy-Crush","Cannon-Balls-3D","Cat-Connection-V2","Cat-Gunner","Cave-Story","Celeste","Cell-Machine","Chat-Room","CheeseRolling","Chess-Classic","Chiikawa-Puzzle","Choppy-Orc","Christmas-Massacre","Chromium-BSU","Clash-Of-Tanks","Clash-Of-Vikings","Clicker-Heroes","Cluster-Rush","ColorWaterSort3D","Cooking-Mama","Core-Ball-Level-4","Count-Masters","Crash-Bandicoot","Crazy-Cars","CrazyCattle3d","CrazyChicken3D","Crossing-The-Pit","Crossy-Road","Crush-The-Castle","Crush-The-Castle-2","Cuphead","Cursed-Treasure","Cursed-Treasure-2","Curve-Rush","Curveball","Cut-The-Rope","Cut-The-Rope-Holiday","Cut-The-Rope-Time-Travel","DONT-YOU-LECTURE-ME-WITH-YOUR-THIRTY-DOLLAR-WEBSITE","Dadish","Dadish-2","Dadish-3","Dan-The-Man","Death-Run-3D","Deep-Sleep-1","Deep-Sleep-2","Deep-Sleep-3","Destroy-The-Car-3D","Dice-a-Million","Dig-Deep","Dig-To-China","Dogeminer","Dont-Escape-1","Dont-Escape-2","Dont-Escape-3","Dont-Whack-Your-Boss","Doodle-Jump","Doom","Doom-3","Dragon-Vs-Bricks","Draw-the-Hill","DrawJoust","Dreadhead-Parkour","Drift-Boss","Drive-Mad","Driven-Wild","Duck-Life","Duck-Life-2","Duck-Life-3","Duck-Life-4","Duck-Life-5","Eaglercraft","Earn-To-Die","Earn-To-Die-2","Earn-to-Die-2-Exodus","Effing-Worms","Eggy-Car","Elastic-Face","ElementalMasters","Endless-Aethos","Endoparasitic","Endoparasitic-2","Escape-Road","Escape-Road-2","Escape-Road-City","Escaping-The-Prison","Evil-Glitch","EvoWarsio","FNAE","FNAF-1","FNAF-2","FNAF-3","FNAF-4","FNAF-Pizzeria-Simulator","FNAF-Sister-Location","FNAF-UCN","FNAF-World","FNF-Cyber-Sensation-Friday-Night-Funkin","FNF-SOFT-Online-Friday-Night-Funkin","FNF-VS-Shaggy","Factory-Balls","Factory-Balls-2","Factory-Balls-3","Factory-Balls-4","Fallout","Fancy-Pants-Adventures","Fashion-Battle","Fat-Cat","Fear-Assessment","Fears-To-F
83athom-Home-Alone","Fears-to-Fathom","Final-Earth-2","Fireboy-and-Watergirl","Fireboy-and-Watergirl-2","Fireboy-and-Watergirl-3","Fireboy-and-Watergirl-4","Fireboy-and-Watergirl-5","Fireboy-and-Watergirl-6","Fishing-Frenzy","Five-Nights-at-Candys-1","Five-Nights-at-Candys-2","Five-Nights-at-Freddys-4-Halloween","Five-Nights-at-Freddys-Pizzeria-Simulator","Five-Nights-at-Shreks-Hotel","Flappy-Bird","Flappy-Bird-Multiplayer","Flappy-Dunk","Flash-Flight-Simulator-1","ForkNSausage","Friday-Night-Funkin-AKAGE","Friday-Night-Funkin-FNF-vs-Tricky-Version-2-Phase-3-w-CHEAT-BOT","Friday-Night-Funkin-Lullaby","Friday-Night-Funkin-Plus-Hatsune-Miku","Friday-Night-Funkin-Psych-Engine","Friday-Night-Funkin-Sarventes-Mid-Fight-Masses","Friday-Night-Funkin-Vs-Nonsense","Funny-Puzzles","Fused-240","Gabriels-Awesome-Schoolhouse","Game-Inside-a-Game","Geometry-Dash-Lite","George-and-the-Printer","Getaway-Shootout","Getting-Over-It","Gobble","Gods-Flesh","Granny","Granny-2","Granny-3","Guess-Their-Answer","Gun-Mayham-2","Gun-Mayham-Redux","GunBuild","Gunblood","HAYAI","HCR-Lite-10","Half-Life","Half-Life-Opposing-Force","Happy-Fishing","Happy-Wheels","HappySheepies","Harvestio","Heartbreak-Havoc","Hedgehog-Launch","HexGL","Hextris","HighHeels","Highway-Racer-2","Hit-Single-Real","Hobo-1","Hobo-2","Hobo-3","Hobo-4","Hobo-5","Hobo-6","Hobo-7","Hoop-Royale","Hotline-Miami","House-of-Hazards","Hyper-Sandbox","I-WANNA-BE-THE-GUY-THE-GAME-THE-MOVIE","Ice-Dodo","Idle-Breakout","Idle-Dice","Idle-Mining-Empire","Indie-Cross","Interactive-Buddy","Into-Space-1","Into-Space-2","Into-Space-3","Iron-Lung","Iron-Snout","Jacksmith","Jelly-Drift","Jelly-Mario","Jelly-Truck","Jetpack-Joyride","Johnny-Upgrade","Just-Fall","Just-Shapes-and-Beats","Karlson","Kindergarten","Kindergarten-2","Kitchen-Bazar","KittyToy","Knights-Arena","Krunker","LETHAL-APE","Laceys-Flash-Games","Learn-To-Fly-2","Learn-To-Fly-3","Level-Devil","Line-Rider-2","Little-Alchemy-2","Little-Runmo-The-Game-13","Lobotomy-Corporation","Look-Outside","Love-Letters","Luminous-Strike","Madness-Project-Nexus","Magic-Tiles-3","Maze-Speedrun","Melon-Playground","Meteor-60-Seconds","Midnight-Shift-12","Milkman-Karlson","Mindustry","Minecraft","Minecraft-Case-Simulator","Minecraft-Online","Minesweeper-Plus","Mini-Metro","Mob-control","Monkey-Mart","Monster-Tracks","Motherload","Moto-X3M-Pool-Party","Moto3XM","Moto3XM-2","MotoX3M-6-Spooky-Land","Mountain-Bike-Racer","Mutilate-A-Doll-Two","Needy-Streamer-Overload","Ninja-vs-EVILCORP","Om-Nom-Run","One-Night-At-Kim-Jong-Uns","OshiOshiPunch","Outhold","OvO","OvO-2","OvO-3","Overburden","PEAK","Pac-Man","Pandemic","Pandemic-2","Papa-Bakes","Papa-Burg","Papa-Cpck","Papa-Htdog","Papa-Scoop","Papas-Cheese","Papas-Donut","Papas-Louie-1","Papas-Louie-2","Papas-Louie-3","Papas-Pasta","Papas-Pizzeria","Papas-PnCk","Papas-Sushi","Papas-Wing","Paper-IO-2","Parking-Rush","Peaks-of-Yore","People-Playground","Pibby-Apocalypse","Pico-vs-uberkids","Picos-school","Picos-school-2","Pizza-Tower","Plague-Inc","Poly-Art-3D","Polytrack-Modded","Polytrack-New","Polytrack-Old","Portal-Flash","Pou","Power-Hover","Powermanga","RERUN","Race-Master","Raft","Raft-Wars","Raft-Wars-2","Ragdoll-Archers","Rainbow-Obby-v03x","Raze","Raze-2","Red-ball","Red-ball-2","Red-ball-3","Red-ball-4","Repo","Retro-Bowl","Retro-Bowl-College","Riddle-School-1","Riddle-School-2","Riddle-School-3","Riddle-School-4","Riddle-School-5","Riddle-School-Transfer","Riddle-School-Transfer-2","Rogue-Sergeant-The-Final-Operation","Rolling-Sky","Rolly-Vortex","Rooftop-Snipers","Rooftop-Snipers-2","Run","Run-2","Run-3","RunRich","SANDTRIS","SLENDYTUBBIES-1","SMB1-Web-Gameplay","Sandstone","Scary-Shawarma-3D","Schoolboy-Runaway","Scratch-Inc","Sentry-Knight","Shady-Bears","Shapez","Shell-Shockers","Shopping-Cart-Hero","Shopping-Cart-Hero-2","Shopping-Cart-Hero-3","Side-Effects","Sift-Heads-1","Sift-Heads-2","Sift-Heads-3","Sift-Heads-4","Sift-Heads-5","Skyball","Slender","Slendytubbies-II-V22","Slider","Slime-Rancher","Slope","Slope-2","Slope-Plus","Slow-Roads","Snail-Bob","Snail-Bob-2","Snail-Bob-3","Snail-Bob-4","Snail-B
83ob-5","Snail-Bob-6","Snail-Bob-7","Snail-Bob-8","Sniper-Assassin","Sniper-assassin-2","Sniper-assassin-3","Sniper-assassin-4","Sniper-assassin-5","Snow-Rider-3D","SnowBattleio","Soccer-Masters-Euro-2020","Soccer-Random","Sonic-2-Communitys-Cut","Sonic-3-AIR","Space-Waves","Spaceflight-Simulator","Spelunky","SpelunkyClassicHD","SpiderDoll","Sprunki","Stardew-Valley","Starfighter","Stealing-The-Diamond","Stick-Madness","Stick-Madness-2","Stick-Merge","Stick-Merge-2","Stick-RPG","Stick-Slasher","Stick-War-1","Stick-War-2","Stickman-Arena","Stickman-Boost","Stickman-Climb","Stickman-Destruction-OnlineGamesio","Stickman-Duel","Stickman-Hook","Storm-The-House","Storm-The-House-2","Strikeforce-Heroes","Strikeforce-Kitty","Strikeforce-Kitty-2","SuikaGame","Super-Mario-63","Super-Mario-Wonder","Super-Meat-Boy","Super-Smash-Flash","Sushi-Roll","Swords-And-Souls","TABS","TG-Playground","Tag","Tallio","Tasty-Pastry-Party","Tattletail","Temple-Run-2","Terraria","Territorialio","Territory-War","Tetris","Thats-Not-My-Neighbor","The-Deadseat","The-Final-Earth-2","The-Impossible-Quiz-2","The-Impossible-Quiz-Deluxe","The-Man-In-The-Window","There-Is-No-Game","This-Is-The-Only-Level","Three-Goblets","Time-Shooter","Time-Shooter-2","Time-Shooter-3","Tiny-Fishing","Tomb-of-the-Mask","Toss-the-turtle","Tower-Crash-3D","Tower-Square","Trigger-Rally","Troll-Face-Quest","Troll-Face-Quest-2","Troll-Face-Quest-3","Troll-Face-Quest-4","Troll-Face-Quest-5","Tunnel-Rush","Turbo-Stars","Ultrakill","Ultrapool","Undertale","Undertale-Yellow","Unfair-mario","Unity-Web-Player-DELTATRAVELER","Unity-Web-Player-Dimension-incident","Unity-Web-Player-FISH","Unity-Web-Player-Flying-Gorilla","Unity-Web-Player-Goblin-Goopmaxxing","Unity-Web-Player-MiSide","Unity-Web-Player-Roulette-Hero","Unity-Web-Player-Shift-at-Midnight","Unity-Web-Player-Swordfight","Untitled-Goose-Game","UvuvwevwevweOnyetenvewv","Vectoroids","Vena","Vex-1","Vex-2","Vex-3","Vex-3-Xmas","Vex-4","Vex-5","Vex-6","Vex-7","Vex-8","Vex-Challenges","Vex-X3M","Vex-X3M-2","Violetland","Volley-Random","Vs-QT-Mod","WeBecomeWhatWeBehold","Weapon-Upgrade-Rush","WebFishing","WebOsu-20","Wheely","Wheely-2","Wheely-3","Wheely-4","Wheely-5","Wheely-6","Wheely-7","Wheely-8","WhosYourDaddy","Witch-Heart","Wordle","Worlds-Hardest-Game","Worlds-Hardest-Game-3","Worlds-Hardest-Game-4","Worst-Time-Simulator","YOMI-HUSTLE","Zombotron","Zombotron-2","beatblock","bob-the-robber-2","circloO","circloO-2-Unblocked-ubg235-Poki","gunspin","hollowknight","journey-downhill","n-gon","qwop","sandspiel","shapez-Demo-Factory-Automation-Game","slitherio"]); 84// ââ END GENERATED ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ 85 86const IMG_BASE = (_isLocal && _localPort) 87 ? `http://localhost:${_localPort}` 88 : `${SHARD_ORIGIN}/${SHARD_DEFAULT}`; 89 90/** Base URL of the shard a game is hosted in. 91 `shard` may be a bare repo name (served from SHARD_ORIGIN) or a full base URL â 92 the numbered shards live on a different account, e.g. 93 "https://freeonlinewebtools.github.io/gamelist9.github.io". */ 94function gameBase(g) { 95 if (_isLocal && _localPort) return `http://localhost:${_localPort}`; 96 const shard = (g && g.shard) || SHARD_DEFAULT; 97 return shard.includes('://') ? shard.replace(/\/$/, '') : `${SHARD_ORIGIN}/${shard}`; 98} 99/** The game's folder on its shard. Still the fallback iframe target. */ 100function gameFolder(g) { return `${gameBase(g)}/${g.url}/`; } 101 102/** The shard's pinned jsDelivr mirror, or '' when it has none. */ 103function gameCdnBase(g) { 104 if (_isLocal && _localPort) return ''; 105 const shard = (g && g.shard) || SHARD_DEFAULT; 106 const repo = shard.includes('://') ? shard.replace(/\/$/, '').split('/').pop() : shard; 107 return SHARD_CDN[repo] || ''; 108} 109 110/** The game's thumbnail, or '' when it has no image. 111 Served from the CDN wherever possible. Thumbnails used to resolve to 112 github.io, which most school filters block â so on the Render host every 113 grid, shelf and recommendation rendered as empty boxes even though the page 114 itself loaded fine. */ 115function gameThumb(g) { 116 if (!g || !g.image) return ''; 117 const cdn = gameCdnBase(g); 118 return cdn ? `${cdn}/${g.url}/${g.image}` : `${gameFolder(g)}${g.image}`; 119} 120 121/** What the player iframe loads. 122 Prefers the local shell at /g/{slug}/, whose assets come from jsDelivr, so no 123 github.io is involved at all â that is what makes the Render host usable. 124 Two deliberate limits: 125 · only for games that actually have a shell; the other ~98 would 404.
126 · not while on github.io. There it buys no reachability (the page itself 127 already came from github.io) and it would move the game to a new origin, 128 orphaning localStorage saves for the ~394 games currently running on the 129 freeonlinewebtools origin. No upside, real downside. */ 130function gamePlayUrl(g) { 131 if (!g) return ''; 132 if (g.embed) return g.embed; 133 const onGithubPages = location.hostname.endsWith('github.io'); 134 if (!onGithubPages && !(_isLocal && _localPort) && PLAY_SHELLS.has(g.url)) { 135 return `/g/${encodeURIComponent(g.url)}/`; 136 } 137 return gameFolder(g); 138} 139 140const PT_KEY = 'ubg_pt'; 141const FAV_KEY = 'ubg_fav'; 142const FAV_LEG = 'favorites'; 143const RATING_KEY = 'ubg_ratings'; 144 145// ââ Favorites Utilities âââââââââââââââââââââââââââââââââââââââ 146const favSet = new Set(JSON.parse(localStorage.getItem(FAV_KEY) || localStorage.getItem(FAV_LEG) || '[]')); 147 148function saveFavs() { 149 localStorage.setItem(FAV_KEY, JSON.stringify([...favSet])); 150} 151 152// Initialize theme on script load 153initTheme();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.