--- import HackCard from '../components/HackCard.astro'; import FilterGroup from '../components/FilterGroup.astro'; import Layout from '../components/Layout.astro'; import { catalog, facetValueSlug, flagshipHacks, getFacetEntries, hacks } from '../lib/site-data'; import type { FacetName } from '../lib/types'; const platforms = getFacetEntries('platform'); const bases = getFacetEntries('base').slice(0, 12); const types = getFacetEntries('type'); const statuses = getFacetEntries('status'); type StatItem = { label: string; count: number; }; type StatGroup = { label: string; icon: string; items: StatItem[]; }; type BrowseGroup = { label: string; facet: Extract; entries: [string, number][]; }; function facetCount(facet: FacetName, value: string): number { return catalog.facets[facet]?.[value] ?? 0; } function displayFacetValue(value: string): string { return value === 'Unknown' ? 'Unclassified' : value; } function selectedItems(facet: FacetName, values: string[]): StatItem[] { return values .map((value) => ({ label: displayFacetValue(value), count: facetCount(facet, value) })) .filter((item) => item.count > 0); } function otherItem(facet: FacetName, selectedValues: string[]): StatItem | undefined { const selected = new Set([...selectedValues, 'Unknown']); const count = getFacetEntries(facet) .filter(([value]) => !selected.has(value)) .reduce((total, [, entryCount]) => total + entryCount, 0); return count > 0 ? { label: 'Other', count } : undefined; } function summaryItems(facet: FacetName, values: string[]): StatItem[] { const items = selectedItems(facet, values); const other = otherItem(facet, values); const unknown = facetCount(facet, 'Unknown'); if (other) items.push(other); if (unknown > 0) items.push({ label: 'Unclassified', count: unknown }); return items; } const statGroups: StatGroup[] = [ { label: 'Platforms', icon: 'platform', items: summaryItems('platform', ['GBA', 'NDS', 'PC', 'GBC']) }, { label: 'Types', icon: 'type', items: summaryItems('type', ['Expansion', 'New Experience', 'Difficulty', 'QoL']) }, { label: 'Status', icon: 'status', items: summaryItems('status', ['Complete', 'Ongoing', 'Beta']) }, ]; const browseGroups: BrowseGroup[] = [ { label: 'Platforms', facet: 'platform', entries: platforms }, { label: 'Types', facet: 'type', entries: types }, { label: 'Status', facet: 'status', entries: statuses }, ]; ---

ROM Hack Archive

A private catalog of {catalog.count} Pokémon ROM hacks, fan-games, patches, notes, guides, and files.

Catalog breakdown
{catalog.count}hacks
{statGroups.map((group) => (
{group.label}
    {group.items.map((item) => (
  • {item.label} {item.count}
  • ))}
))}

Flagship Picks

Known anchors from the collection.

{flagshipHacks.map((hack) => )}

Browse the archive

Jump into grouped catalog views without privileging a single platform or play style.

{browseGroups.map((group) => (

{group.label}

))}

All Hacks

{hacks.length} shown
{hacks.map((hack) => )}