data: add Pokemblem to catalog + bump fixture counts

FE8 crossover hack (self-hosted in-game banner). Catalog 404 -> 405;
Playwright fixtures updated (405, GBA 204, New Experience 174, Complete 342).
Built and deployed to romhacks.ginnoir.com.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ginnoir
2026-07-06 19:25:10 -05:00
co-authored by Claude Opus 4.8
parent 3562042bc7
commit 70d46933bd
3 changed files with 69 additions and 14 deletions
+60 -6
View File
@@ -1,9 +1,9 @@
{ {
"generated": "2026-07-06", "generated": "2026-07-06",
"count": 404, "count": 405,
"facets": { "facets": {
"platform": { "platform": {
"GBA": 203, "GBA": 204,
"PC": 83, "PC": 83,
"NDS": 50, "NDS": 50,
"GBC": 37, "GBC": 37,
@@ -50,6 +50,7 @@
"Brilliant Diamond / Shining Pearl": 1, "Brilliant Diamond / Shining Pearl": 1,
"Conquest": 1, "Conquest": 1,
"Emerald (TrashMan)": 1, "Emerald (TrashMan)": 1,
"Fire Emblem: The Sacred Stones": 1,
"FireRed / LeafGreen": 1, "FireRed / LeafGreen": 1,
"Let's Go Pikachu / Eevee": 1, "Let's Go Pikachu / Eevee": 1,
"Moon": 1, "Moon": 1,
@@ -63,7 +64,7 @@
"Ultra Sun": 1 "Ultra Sun": 1
}, },
"status": { "status": {
"Complete": 341, "Complete": 342,
"Beta": 32, "Beta": 32,
"Ongoing": 30, "Ongoing": 30,
"Complete (beta)": 1 "Complete (beta)": 1
@@ -81,7 +82,7 @@
"pokeemerald (decomp, likely)": 1 "pokeemerald (decomp, likely)": 1
}, },
"type": { "type": {
"New Experience": 173, "New Experience": 174,
"Expansion": 166, "Expansion": 166,
"Difficulty": 127, "Difficulty": 127,
"QoL": 94, "QoL": 94,
@@ -89,10 +90,10 @@
"Cosmetic": 13, "Cosmetic": 13,
"Demake": 11, "Demake": 11,
"Roguelite": 7, "Roguelite": 7,
"Crossover": 1 "Crossover": 2
}, },
"play_status": { "play_status": {
"Unplayed": 394, "Unplayed": 395,
"Completed": 5, "Completed": 5,
"Backlog": 3, "Backlog": 3,
"Dropped": 1, "Dropped": 1,
@@ -15227,6 +15228,59 @@
} }
] ]
}, },
{
"stem": "Pokemblem",
"title": "Pokemblem",
"platform": "GBA",
"base": "Fire Emblem: The Sacred Stones",
"version": "1.20",
"status": "Complete",
"generation": "Gen I",
"fakemon": "No",
"developer": "Vesly",
"release_date": "2025",
"banner": "https://romhacks-files.ginnoir.com/_meta/Pokemblem/banner.png",
"homepage": "https://feuniverse.us/t/pokemblem-complete-v1-20/8875",
"source": "https://feuniverse.us/t/pokemblem-complete-v1-20/8875",
"library_path": "roms/gba/Pokemblem [Hack].gba",
"play_status": "Unplayed",
"generations": [
"Gen I"
],
"type": [
"New Experience",
"Crossover"
],
"tags": [
"hack",
"platform/gba",
"base/fireemblem",
"status/complete",
"type/newexperience",
"type/crossover",
"source/feuniverse"
],
"summary": "Pokemblem is Vesly's completed crossover hack that reimagines Pokémon Generation 1 on top of Fire Emblem: The Sacred Stones (GBA). It swaps Pokémon's turn-based duels for Fire Emblem's grid-based tactical combat — you re-live the Kanto journey, catch Pokémon, and fight with your whole party at once, where positioning and team composition matter more than grinding. A genre-bending oddball and intentionally the only non-Pokémon-engine entry in the library.",
"notability": "",
"story": "Re-live your journey through Kanto in this reimagining of Pokémon. Battle with your whole party at once, and devise strategies to take down the toughest foes. The narrative is sparse and mostly optional — the focus is squarely on the tactics.",
"features": [
"Grid-based Fire Emblem tactical combat with your full party fighting simultaneously.",
"Pokémon catching and an evolution system, with RPG-style overworld walking/exploration.",
"Type effectiveness/resistance, area-of-effect attacks, equippable accessories, and level-up moves, TMs, and Skill Scrolls.",
"Trainer battles, multiple playtested difficulty levels, and a Randomizer mode.",
"QoL: in-game learnset menu, fast-travel via route signs, experience capped to gym-leader levels, and nearly every Pokémon kept viable."
],
"links": [
{
"label": "FEUniverse thread",
"url": "https://feuniverse.us/t/pokemblem-complete-v1-20/8875"
},
{
"label": "Trailer",
"url": "https://www.youtube.com/watch?v=hifN8fICsKs"
}
]
},
{ {
"stem": "Poketale", "stem": "Poketale",
"title": "Pokémon Poketale", "title": "Pokémon Poketale",
+1
View File
@@ -253,6 +253,7 @@
"platinum-redux": "/assets/banners/platinum-redux.jpg", "platinum-redux": "/assets/banners/platinum-redux.jpg",
"platinum-unlocked": "/assets/banners/platinum-unlocked.jpg", "platinum-unlocked": "/assets/banners/platinum-unlocked.jpg",
"pocket-gaiden": "/assets/banners/pocket-gaiden.webp", "pocket-gaiden": "/assets/banners/pocket-gaiden.webp",
"pokemblem": "/assets/banners/pokemblem.png",
"poketale": "/assets/banners/poketale.png", "poketale": "/assets/banners/poketale.png",
"poketropolis": "/assets/banners/poketropolis.img", "poketropolis": "/assets/banners/poketropolis.img",
"pokerogue": "/assets/banners/pokerogue.jpg", "pokerogue": "/assets/banners/pokerogue.jpg",
+8 -8
View File
@@ -11,20 +11,20 @@ test('homepage presents balanced navigation and facet summaries', async ({ page
await expect(primaryNav.getByRole('link', { name: 'Difficulty' })).toHaveCount(0); await expect(primaryNav.getByRole('link', { name: 'Difficulty' })).toHaveCount(0);
const heroStats = page.locator('.hero-stats'); const heroStats = page.locator('.hero-stats');
await expect(heroStats).toContainText('404'); await expect(heroStats).toContainText('405');
await expect(heroStats).toContainText('hacks'); await expect(heroStats).toContainText('hacks');
await expect(heroStats).toContainText('Platforms'); await expect(heroStats).toContainText('Platforms');
await expect(heroStats).toContainText('GBA 203'); await expect(heroStats).toContainText('GBA 204');
await expect(heroStats).toContainText('PC 83'); await expect(heroStats).toContainText('PC 83');
await expect(heroStats).toContainText('NDS 50'); await expect(heroStats).toContainText('NDS 50');
await expect(heroStats).toContainText('GBC 37'); await expect(heroStats).toContainText('GBC 37');
await expect(heroStats).toContainText('Types'); await expect(heroStats).toContainText('Types');
await expect(heroStats).toContainText('Expansion 166'); await expect(heroStats).toContainText('Expansion 166');
await expect(heroStats).toContainText('New Experience 173'); await expect(heroStats).toContainText('New Experience 174');
await expect(heroStats).toContainText('Difficulty 127'); await expect(heroStats).toContainText('Difficulty 127');
await expect(heroStats).toContainText('QoL 94'); await expect(heroStats).toContainText('QoL 94');
await expect(heroStats).toContainText('Status'); await expect(heroStats).toContainText('Status');
await expect(heroStats).toContainText('Complete 341'); await expect(heroStats).toContainText('Complete 342');
await expect(heroStats).toContainText('Ongoing 30'); await expect(heroStats).toContainText('Ongoing 30');
await expect(heroStats).toContainText('Beta 32'); await expect(heroStats).toContainText('Beta 32');
}); });
@@ -71,12 +71,12 @@ test('homepage browse summary links to grouped facet pages', async ({ page }) =>
const browse = page.getByRole('region', { name: 'Browse by catalog facets' }); const browse = page.getByRole('region', { name: 'Browse by catalog facets' });
await expect(browse.getByRole('heading', { name: 'Browse the archive' })).toBeVisible(); await expect(browse.getByRole('heading', { name: 'Browse the archive' })).toBeVisible();
await expect(browse.getByRole('link', { name: /GBA\s+203/ })).toHaveAttribute('href', '/browse/platform/gba/'); await expect(browse.getByRole('link', { name: /GBA\s+204/ })).toHaveAttribute('href', '/browse/platform/gba/');
await expect(browse.getByRole('link', { name: /Difficulty\s+127/ })).toHaveAttribute( await expect(browse.getByRole('link', { name: /Difficulty\s+127/ })).toHaveAttribute(
'href', 'href',
'/browse/type/difficulty/', '/browse/type/difficulty/',
); );
await expect(browse.getByRole('link', { name: /Complete\s+341/ })).toHaveAttribute( await expect(browse.getByRole('link', { name: /Complete\s+342/ })).toHaveAttribute(
'href', 'href',
'/browse/status/complete/', '/browse/status/complete/',
); );
@@ -88,7 +88,7 @@ test('catalog search and filters update visible card count', async ({ page }) =>
await expect(page).toHaveTitle(/ROM Hack Archive/); await expect(page).toHaveTitle(/ROM Hack Archive/);
await expect(page.getByRole('heading', { name: 'ROM Hack Archive' })).toBeVisible(); await expect(page.getByRole('heading', { name: 'ROM Hack Archive' })).toBeVisible();
const catalogCards = page.locator('[data-card-grid] [data-card]:visible'); const catalogCards = page.locator('[data-card-grid] [data-card]:visible');
await expect(catalogCards).toHaveCount(404); await expect(catalogCards).toHaveCount(405);
await page.getByPlaceholder('Search hacks').fill('Radical Red'); await page.getByPlaceholder('Search hacks').fill('Radical Red');
await expect(catalogCards).toHaveCount(5); await expect(catalogCards).toHaveCount(5);
@@ -96,7 +96,7 @@ test('catalog search and filters update visible card count', async ({ page }) =>
await page.getByPlaceholder('Search hacks').fill(''); await page.getByPlaceholder('Search hacks').fill('');
await page.getByLabel('GBA').check(); await page.getByLabel('GBA').check();
await expect(catalogCards).toHaveCount(203); await expect(catalogCards).toHaveCount(204);
await page.getByLabel('Difficulty').check(); await page.getByLabel('Difficulty').check();
await expect(catalogCards.first()).toBeVisible(); await expect(catalogCards.first()).toBeVisible();