Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
f6b3d48
add script to check missing sprites
anhthang Feb 14, 2026
e3a2ae7
add missing front, front shiny sprites
anhthang Feb 14, 2026
24c4a7d
add gen 6 back
anhthang Feb 14, 2026
28138c5
add missing gen 8 sprites
anhthang Feb 14, 2026
d0019b1
add missing gen 6 shiny back
anhthang Feb 14, 2026
f83c0e6
ruff format
anhthang Feb 14, 2026
7803221
fix: optimize sprite renaming with species-form fallback and cleaner …
anhthang Feb 16, 2026
bb09490
fixing silvally sprites
anhthang Feb 16, 2026
6fe29f5
add missing alcremie sprites
anhthang Feb 16, 2026
c88fcba
add missing pikachu region cap
anhthang Feb 16, 2026
f3e45df
final addition
anhthang Feb 17, 2026
a10cc00
fix: front sceptile mega
anhthang Feb 17, 2026
e51586f
rerun gen9 and update all sprites from latest
anhthang Feb 20, 2026
1b86cac
fix Xerneas
anhthang Feb 20, 2026
491b447
rename to correct pokemon id, remove some duplicate images
anhthang Feb 20, 2026
cc10418
rename part 2
anhthang Feb 20, 2026
1b2dc22
fix xerneas shiny
anhthang Feb 20, 2026
9dbc174
revert ampharos mega
anhthang Feb 20, 2026
8a2886d
fix Zarude-dada back
anhthang Feb 20, 2026
7dd1eb1
fix shiny rotom
anhthang Feb 20, 2026
98b7acb
fix: rapidash, zorua color update
anhthang Feb 24, 2026
9880d09
chore: add contributing document
anhthang Mar 3, 2026
3b7ab05
fix: consolidate missing sprite checks into single report
anhthang Mar 3, 2026
08039c8
fix: use pathlib, get csv data from upstream, add more comment for ex…
anhthang Mar 3, 2026
e9ad275
add sort forms to make it consistent later
anhthang Mar 4, 2026
0692132
fix: do not copy if no suffix found to prevent overritting default po…
anhthang Mar 4, 2026
4a000df
fix: palafin
anhthang Mar 4, 2026
242b4b9
revert to ogerpon mask
anhthang Mar 5, 2026
3e63869
fix: clarify the logic for renaming to id-formname format
anhthang Mar 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ desktop.ini
# Versioning
.svn/
.git/

smogon/
scripts/downloads/
65 changes: 65 additions & 0 deletions CONTRIBUTING_SPRITES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Contributing Sprites

## Overview

This repository provides helper scripts and documentation to manually maintain the default sprite collection located in `sprites/pokemon/`. Our goal is to provide a complete set of "Gen 5 style" (Black & White) sprites for the entire National Dex.

This initial version of the maintenance workflow focuses specifically on:

1. **Auditing** the `sprites/pokemon/` folder for missing assets.
2. **Synchronizing** with Smogon community spreadsheets for Pokémon with **IDs 650+** (National Dex entries beyond the official Gen 5 games).

## Missing Sprites Tracking and Smogon Synchronization

### 1. Identifying Missing Sprites

**Script:** `scripts/check_missing_sprites.py`

This script identifies which Pokémon or forms are missing from the `sprites/pokemon/` directory.

* **Data Sources:** It references `pokemon.csv` and `pokemon_forms.csv` from the PokéAPI database.
* **Logic:** It checks for the existence of four primary assets for every entry:
* Front (Default & Shiny)
* Back (Default & Shiny)
* **Output:** Missing entries are logged in `missing_sprites.csv` to track our progress toward a 100% complete National Dex.

### 2. Synchronizing with Smogon

**Script:** `scripts/smogon_download.py`

Since official Gen 5 sprites do not exist for newer Pokémon, we source community-made assets from Smogon. This script automates the download and renaming process.

#### Filename Mapping

Smogon uses a shorthand naming system. The script (utilizing logic from `renameSmogon.sh`) translates these into the PokéAPI structure:

| Suffix | Sprite Type | Example |
| --- | --- | --- |
| *(None)* | Front Default | `100.png` |
| `s` | Front Shiny | `100s.png` |
| `b` | Back Default | `100b.png` |
| `sb` | Back Shiny | `100sb.png` |
| `g` | Gigantamax | `100g.png` |
| `_1` | Variant/Form | `100_1.png` |

### 3. Mandatory Manual Verification

The Smogon source data is community-maintained and contains known inconsistencies. **The scripts do not handle these automatically.** Contributors must manually review and correct the following:

### Known Data Quirks

* **Orientation Swaps:** Some filenames are reversed in the source.
* *Example:* For **Blastoise**, `009_2.png` is often the **Back** sprite despite being labeled as a front variant.
* **Action:** Verify the image visually and ensure it is placed in the correct directory.

* **Duplicate Variant IDs:** Different forms may share the same numerical suffix in Smogon spreadsheets.
* *Example:* Both **Hoenn Cap** and **Partner Cap** Pikachu may use `_8`.
* **Action:** Cross-reference with the spreadsheet context and manually rename files to match their unique PokéAPI form IDs.

* **Form Mapping:** Ensure variants (e.g., `_1`, `_2`) are correctly mapped using `forms.json`. If a new form is added, you must update `forms.json` manually.

### How to Use

1. **Check for gaps:** `python scripts/check_missing_sprites.py`
2. **Sync Smogon assets:** `python scripts/smogon_download.py`
3. **Manual Fixes:** Review the downloaded files against the "Known Issues" above and correct names/folders manually before submitting a PR.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ sprites

### `pokemon`

Interested in helping us complete the default Gen 5 style sprite collection? See [CONTRIBUTING_SPRITES.md](./CONTRIBUTING_SPRITES.md) for details on our maintenance scripts for National Dex 650+.

#### `other`

##### `dream-world`
Expand Down
108 changes: 108 additions & 0 deletions scripts/check_missing_sprites.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import pandas as pd
from pathlib import Path

# CONFIGURATION
GITHUB_BASE_URL = "https://raw.githubusercontent.com/PokeAPI/pokeapi/master/data/v2/csv"
POKEMON_CSV_URL = f"{GITHUB_BASE_URL}/pokemon.csv"
FORMS_CSV_URL = f"{GITHUB_BASE_URL}/pokemon_forms.csv"
VG_CSV_URL = f"{GITHUB_BASE_URL}/version_groups.csv"

# Local Sprite directories relative to this script
# .parent.parent refers to /Parent/ (going up from /Parent/sprites/scripts/)
SCRIPT_DIR = Path(__file__).resolve().parent
BASE_PATH = SCRIPT_DIR.parent / "sprites" / "pokemon"

PATHS = {
"Front": BASE_PATH,
"Front Shiny": BASE_PATH / "shiny",
"Back": BASE_PATH / "back",
"Back Shiny": BASE_PATH / "back" / "shiny",
}


def check_sprites():
# 1. Load Data from GitHub
print("🌐 Fetching latest Pokémon data from GitHub...")
try:
df_pokemon = pd.read_csv(POKEMON_CSV_URL)
df_forms = pd.read_csv(FORMS_CSV_URL)
df_vg = pd.read_csv(VG_CSV_URL)
except Exception as e:
print(f"❌ Error fetching data: {e}")
return

# 2. Merge Data
print("🔍 Processing data and identifying versions...")

# Get generation info via forms
df_forms_subset = df_forms[df_forms["is_default"] == 1][
["pokemon_id", "introduced_in_version_group_id"]
]

df_merged = df_pokemon.merge(
df_forms_subset, left_on="id", right_on="pokemon_id", how="left"
)
df_merged = df_merged.merge(
df_vg[["id", "generation_id"]],
left_on="introduced_in_version_group_id",
right_on="id",
how="left",
)

pokemon_entries = (
df_merged[["id_x", "species_id", "identifier", "generation_id"]]
.rename(columns={"id_x": "pokemon_id", "generation_id": "generation"})
.to_dict("records")
)

# 3. Check Local Files
print(f"🧪 Scanning local folders for {len(pokemon_entries)} Pokémon...")

all_missing = []

for pokemon in pokemon_entries:
p_id = pokemon["pokemon_id"]
s_id = pokemon["species_id"]
name = pokemon["identifier"]
gen = (
int(pokemon["generation"])
if pd.notnull(pokemon["generation"])
else "Unknown"
)
filename = f"{p_id}.png"

for label, folder in PATHS.items():
file_path = folder / filename

if not file_path.exists():
all_missing.append(
{
"pokemon_id": p_id,
"identifier": name,
"species_id": s_id,
"sprite_type": label.lower().replace(" ", "_"),
"generation": gen,
}
)

# 4. Save and Report
if all_missing:
df_missing = pd.DataFrame(all_missing)
df_missing = df_missing.sort_values(by=["pokemon_id", "sprite_type"])

output_path = SCRIPT_DIR / "missing_sprites.csv"
df_missing.to_csv(output_path, index=False)

print("\n" + "=" * 50)
print(f"✅ REPORT GENERATED: {output_path.name}")
print(f"❌ Total Missing Assets: {len(df_missing)}")
print("=" * 50)
print(df_missing.head(10).to_string(index=False))
if len(df_missing) > 10:
print(f"... and {len(df_missing) - 10} more.")
else:
print("\n✅ All assets present! Your collection is complete.")


if __name__ == "__main__":
check_sprites()
Loading