Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions games/gnmath/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GN Math Games | Verdis</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background: #0f172a;
}
iframe {
border: none;
width: 100%;
height: 100vh;
display: block;
}
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
background: linear-gradient(135deg, #fc2651 0%, #e91e47 100%);
color: white;
padding: 12px 20px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1);
z-index: 1000;
}
.header h1 {
margin: 0;
font-size: 20px;
font-weight: 700;
}
.header a {
color: white;
text-decoration: none;
background: rgba(255, 255, 255, 0.1);
padding: 8px 16px;
border-radius: 8px;
font-size: 14px;
font-weight: 600;
transition: all 0.3s;
}
.header a:hover {
background: rgba(255, 255, 255, 0.2);
transform: translateY(-1px);
}
#gameFrame {
margin-top: 50px;
height: calc(100vh - 50px);
}
.loader {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: Arial, sans-serif;
font-size: 18px;
text-align: center;
}
</style>
</head>
<body>
<div class="header">
<h1>GN Math Games Collection</h1>
<a href="../index.html">← Back to Verdis</a>
</div>

<div class="loader" id="loader">
<div>Loading GN Math...</div>
<div style="font-size: 14px; margin-top: 10px; opacity: 0.8;">Access hundreds of games!</div>
</div>

<iframe id="gameFrame" allow="fullscreen; gamepad; microphone"></iframe>

<script>
// Load GN Math site
const gnmathURL = 'https://gn-math.github.io/';

window.addEventListener('DOMContentLoaded', function() {
const iframe = document.getElementById('gameFrame');
const loader = document.getElementById('loader');

iframe.src = gnmathURL;

iframe.onload = function() {
loader.style.display = 'none';
};

// Hide loader after 3 seconds even if iframe doesn't load
setTimeout(() => {
loader.style.display = 'none';
}, 3000);
});
</script>
</body>
</html>
7 changes: 7 additions & 0 deletions games/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -1363,6 +1363,13 @@ <h2>getaway shootout</h2>
</div>
</a>

<a target="_blank" href="gnmath/index.html">
<div class="button" style="background-image: url('../images/thumbnails/gnmath.svg');" data-genre="arcade">
<h2>gn-math games</h2>
<span class="pin-button"><img src="/images/other/star.png" width="25px" height="25px"></span>
</div>
</a>

<a target="_blank" href="rabbitsamurai/index.html">
<div class="button" style="background-image: url('../images/thumbnails/rabbitsamurai.jpg');" data-genre="platformer">
<h2>rabbit samurai</h2>
Expand Down
19 changes: 19 additions & 0 deletions images/thumbnails/gnmath.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
132 changes: 132 additions & 0 deletions scripts/add-gnmath-games.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env node

/**
* Script to add GN Math games to Verdis
* Since we can't fetch zones.json externally, this uses a curated list
* of popular GN Math games and creates wrapper pages for them
*/

const fs = require('fs');
const path = require('path');

// Popular GN Math games (sample list - would normally come from zones.json)
// Format: { id, name, genre, special tags }
const GNMATH_GAMES = [
{ id: 1, name: "Drive Mad", genre: "arcade", tags: ["popular", "driving"] },
{ id: 2, name: "Crazy Cattle 3D", genre: "arcade", tags: ["3d"] },
{ id: 3, name: "Moto X3M", genre: "arcade", tags: ["popular", "driving"] },
{ id: 4, name: "Tunnel Rush", genre: "arcade", tags: ["popular", "3d"] },
{ id: 5, name: "Vex 5", genre: "platformer", tags: ["popular"] },
{ id: 6, name: "Vex 6", genre: "platformer", tags: ["popular"] },
{ id: 7, name: "Vex 7", genre: "platformer", tags: ["popular"] },
{ id: 8, name: "Slope", genre: "arcade", tags: ["popular", "3d"] },
{ id: 9, name: "Run 3", genre: "platformer", tags: ["popular"] },
{ id: 10, name: "Geometry Dash", genre: "platformer", tags: ["popular"] },
];

function normalizeGameName(name) {
return name.toLowerCase()
.replace(/[^a-z0-9\s]/g, '')
.replace(/\s+/g, '');
}

function createGameHTML(game) {
const template = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>${game.name} | Verdis</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background: #000;
}
iframe {
border: none;
width: 100%;
height: 100vh;
display: block;
}
.loader {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: Arial, sans-serif;
font-size: 20px;
}
</style>
</head>
<body>
<div class="loader">Loading ${game.name}...</div>
<iframe id="gameFrame" allow="fullscreen"></iframe>

<script>
// Load game from GN Math CDN
const gameId = ${game.id};
const gnmathURL = 'https://cdn.jsdelivr.net/gh/gn-math/html@main/' + gameId + '.html';

window.addEventListener('DOMContentLoaded', function() {
const iframe = document.getElementById('gameFrame');
iframe.src = gnmathURL;

iframe.onload = function() {
document.querySelector('.loader').style.display = 'none';
};
});
</script>
</body>
</html>`;
return template;
}

async function main() {
const gamesDir = path.join(__dirname, '..', 'games');
const existingGames = fs.readdirSync(gamesDir)
.filter(f => {
const fullPath = path.join(gamesDir, f);
return fs.statSync(fullPath).isDirectory();
});

console.log(`Found ${existingGames.length} existing games`);

let added = 0;
let skipped = 0;

for (const game of GNMATH_GAMES) {
const dirName = normalizeGameName(game.name);

// Check if game already exists
if (existingGames.includes(dirName)) {
console.log(`⏭️ Skipping "${game.name}" - already exists`);
skipped++;
continue;
}

// Create game directory
const gameDir = path.join(gamesDir, dirName);
fs.mkdirSync(gameDir, { recursive: true });

// Create index.html
const htmlContent = createGameHTML(game);
const htmlPath = path.join(gameDir, 'index.html');
fs.writeFileSync(htmlPath, htmlContent);

console.log(`✅ Added "${game.name}" (${dirName})`);
added++;
}

console.log(`\n=== Summary ===`);
console.log(`Games added: ${added}`);
console.log(`Games skipped (duplicates): ${skipped}`);
console.log(`\nNext steps:`);
console.log(`1. Add game entries to games/index.html`);
console.log(`2. Add thumbnail images to images/thumbnails/`);
console.log(`3. Test the games load correctly`);
}

main().catch(console.error);
91 changes: 91 additions & 0 deletions scripts/fetch-gnmath-games.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
#!/usr/bin/env node

/**
* Script to fetch GN Math games and add them to Verdis
* This script will:
* 1. Fetch the zones.json from GN Math
* 2. Check for duplicates against existing Verdis games
* 3. Generate game entries for games/index.html
*/

const https = require('https');
const fs = require('fs');
const path = require('path');

const ZONES_URL = 'https://cdn.jsdelivr.net/gh/gn-math/assets@main/zones.json';
const COVER_URL = 'https://cdn.jsdelivr.net/gh/gn-math/covers@main';
const HTML_URL = 'https://cdn.jsdelivr.net/gh/gn-math/html@main';

function fetchJSON(url) {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
try {
resolve(JSON.parse(data));
} catch (e) {
reject(e);
}
});
}).on('error', reject);
});
}

function normalizeGameName(name) {
// Convert game name to directory-friendly format
return name.toLowerCase()
.replace(/[^a-z0-9\s]/g, '')
.replace(/\s+/g, '');
}

async function main() {
console.log('Fetching GN Math games list...');

try {
const zones = await fetchJSON(ZONES_URL);
console.log(`Found ${zones.length} games from GN Math`);

// Get existing game directories
const gamesDir = path.join(__dirname, '..', 'games');
const existingGames = fs.readdirSync(gamesDir)
.filter(f => fs.statSync(path.join(gamesDir, f)).isDirectory());

console.log(`Found ${existingGames.length} existing games in Verdis`);

// Filter out duplicates and special entries
const newGames = zones.filter(zone => {
const normalizedName = normalizeGameName(zone.name);
const isDuplicate = existingGames.includes(normalizedName);
const isExternal = zone.url && zone.url.startsWith('http');
return !isDuplicate && !isExternal;
});

console.log(`${newGames.length} new games to add (after filtering duplicates and external links)`);

// Output game data as JSON for further processing
const outputPath = path.join(__dirname, 'gnmath-games.json');
fs.writeFileSync(outputPath, JSON.stringify(newGames, null, 2));
console.log(`Game data saved to ${outputPath}`);

// Generate summary
console.log('\n=== Summary ===');
console.log(`Total GN Math games: ${zones.length}`);
console.log(`Existing Verdis games: ${existingGames.length}`);
console.log(`New games to add: ${newGames.length}`);
console.log(`Skipped (duplicates or external): ${zones.length - newGames.length}`);

if (newGames.length > 0) {
console.log('\n=== Sample of new games ===');
newGames.slice(0, 10).forEach(game => {
console.log(` - ${game.name} (ID: ${game.id})`);
});
}

} catch (error) {
console.error('Error:', error.message);
process.exit(1);
}
}

main();