Skip to content
Open
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
14 changes: 14 additions & 0 deletions css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,20 @@ html, body {
max-width: 60%;
}

/* ===== DESCRIPTION ===== */
#stats-description {
font-size: 0.8rem;
font-style: italic;
color: rgba(255, 255, 255, 0.65);
line-height: 1.5;
margin: 10px 0 14px;
padding: 0 2px;
}

#stats-description:empty {
display: none;
}

/* ===== STAT BARS ===== */
#stats-bars {
display: flex;
Expand Down
25 changes: 25 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,18 @@ <h1 id="pokemon-name"></h1>
<span class="info-label">Dex #</span>
<span id="stats-dex" class="info-value"></span>
</div>
<div class="info-row">
<span class="info-label">Category</span>
<span id="stats-category" class="info-value"></span>
</div>
<div class="info-row">
<span class="info-label">Generation</span>
<span id="stats-gen" class="info-value"></span>
</div>
<div class="info-row">
<span class="info-label">Region</span>
<span id="stats-region" class="info-value"></span>
</div>
<div class="info-row">
<span class="info-label">Height</span>
<span id="stats-height" class="info-value"></span>
Expand All @@ -52,7 +60,24 @@ <h1 id="pokemon-name"></h1>
<span class="info-label">Abilities</span>
<span id="stats-abilities" class="info-value"></span>
</div>
<div class="info-row">
<span class="info-label">Catch Rate</span>
<span id="stats-catch-rate" class="info-value"></span>
</div>
<div class="info-row">
<span class="info-label">Base Exp</span>
<span id="stats-base-exp" class="info-value"></span>
</div>
<div class="info-row">
<span class="info-label">Happiness</span>
<span id="stats-happiness" class="info-value"></span>
</div>
<div class="info-row">
<span class="info-label">Growth Rate</span>
<span id="stats-growth-rate" class="info-value"></span>
</div>
</div>
<div id="stats-description"></div>
<div id="stats-bars">
<div class="stat-row"><span class="stat-label">HP</span><div class="stat-bar-bg"><div class="stat-bar" data-stat="hp"></div></div><span class="stat-value" data-stat="hp"></span></div>
<div class="stat-row"><span class="stat-label">ATK</span><div class="stat-bar-bg"><div class="stat-bar" data-stat="atk"></div></div><span class="stat-value" data-stat="atk"></span></div>
Expand Down
43 changes: 43 additions & 0 deletions js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,19 @@
const statsHeight = document.getElementById("stats-height");
const statsWeight = document.getElementById("stats-weight");
const statsAbilities = document.getElementById("stats-abilities");
const statsCategory = document.getElementById("stats-category");
const statsRegion = document.getElementById("stats-region");
const statsCatchRate = document.getElementById("stats-catch-rate");
const statsBaseExp = document.getElementById("stats-base-exp");
const statsHappiness = document.getElementById("stats-happiness");
const statsGrowthRate = document.getElementById("stats-growth-rate");
const statsDescription = document.getElementById("stats-description");
const spinButton = document.getElementById("spin-button");

// ===== STATE =====
let isSpinning = false;
let audioContext = null;
let revealedPokemonId = null;

// ===== AUDIO ENGINE (Web Audio API) =====
function getAudioContext() {
Expand Down Expand Up @@ -165,6 +173,21 @@
return colors[statIndex];
}

function getRegionName(gen) {
const regions = {
1: "Kanto",
2: "Johto",
3: "Hoenn",
4: "Sinnoh",
5: "Unova",
6: "Kalos",
7: "Alola",
8: "Galar",
9: "Paldea",
};
return regions[gen] || "Unknown";
}

// ===== UPDATE DISPLAY =====
function showPokemon(pokemon, isReveal) {
const imgUrl = getImageUrl(pokemon.id);
Expand Down Expand Up @@ -203,10 +226,19 @@

// Info
statsDex.textContent = `#${pokemon.dex.toString().padStart(4, "0")}`;
statsCategory.textContent = pokemon.category || "";
statsGen.textContent = `Gen ${getGenRoman(pokemon.gen)}`;
statsRegion.textContent = getRegionName(pokemon.gen);
statsHeight.textContent = formatHeight(pokemon.height);
statsWeight.textContent = formatWeight(pokemon.weight);
statsAbilities.textContent = pokemon.abilities.join(", ");
statsCatchRate.textContent = pokemon.catchRate;
statsBaseExp.textContent = pokemon.baseExp;
statsHappiness.textContent = pokemon.baseHappiness;
statsGrowthRate.textContent = pokemon.growthRate || "";

// Description
statsDescription.textContent = pokemon.description || "";

// Stat bars
const statNames = ["hp", "atk", "def", "spa", "spd", "spe"];
Expand Down Expand Up @@ -264,6 +296,7 @@
placeholderText.classList.add("hidden");
hideStats();
spinButton.classList.add("spinning");
revealedPokemonId = null;

// Pick the final result upfront
const finalPokemon = getRandomPokemon();
Expand Down Expand Up @@ -341,6 +374,9 @@
playCry(pokemon.id);
}, 300);

// Store for click-to-replay cry
revealedPokemonId = pokemon.id;

// Show stats with delay for dramatic effect
setTimeout(() => {
showStats(pokemon);
Expand All @@ -355,6 +391,13 @@
// ===== EVENT LISTENERS =====
spinButton.addEventListener("click", spin);

// Click Pokémon image to replay cry
pokemonImage.addEventListener("click", () => {
if (!isSpinning && revealedPokemonId !== null) {
playCry(revealedPokemonId);
}
});

// Also allow spacebar / enter to spin
document.addEventListener("keydown", (e) => {
if (e.key === " " || e.key === "Enter") {
Expand Down
2 changes: 1 addition & 1 deletion js/pokemon-data.js

Large diffs are not rendered by default.

62 changes: 60 additions & 2 deletions scripts/generate_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@
"ability_names.csv",
"type_names.csv",
"pokemon_form_names.csv",
"pokemon_species_names.csv",
"pokemon_species_flavor_text.csv",
"growth_rates.csv",
"growth_rate_prose.csv",
]

# Gen 9 max species ID (through Pecharunt #1025)
Expand Down Expand Up @@ -235,7 +239,7 @@ def main():
print("\nProcessing data...\n")

# Build lookup tables
# Species: id -> {generation_id, color_id, identifier}
# Species: id -> {generation_id, color_id, identifier, capture_rate, base_happiness, growth_rate_id}
species_map = {}
for row in data["pokemon_species.csv"]:
sid = int(row["id"])
Expand All @@ -244,6 +248,9 @@ def main():
"gen": int(row["generation_id"]),
"color_id": int(row["color_id"]),
"name": row["identifier"],
"capture_rate": int(row.get("capture_rate", 0)),
"base_happiness": int(row.get("base_happiness", 0) or 0),
"growth_rate_id": int(row.get("growth_rate_id", 1)),
}

# Colors: id -> name
Expand Down Expand Up @@ -273,7 +280,7 @@ def main():
if row["local_language_id"] == ENGLISH_LANG_ID:
ability_display[int(row["ability_id"])] = row["name"]

# Pokemon: id -> {species_id, height, weight, identifier, is_default}
# Pokemon: id -> {species_id, height, weight, identifier, is_default, base_experience}
pokemon_map = {}
for row in data["pokemon.csv"]:
pid = int(row["id"])
Expand All @@ -285,6 +292,7 @@ def main():
"weight": int(row["weight"]),
"identifier": row["identifier"],
"is_default": row["is_default"] == "1",
"base_experience": int(row.get("base_experience", 0) or 0),
}

# Stats: pokemon_id -> {hp, atk, def, spa, spd, spe}
Expand Down Expand Up @@ -345,6 +353,50 @@ def main():
if name:
form_names_map[fid] = name

# Genus (category): species_id -> English genus (e.g. "Seed Pokémon")
genus_map = {}
for row in data["pokemon_species_names.csv"]:
if row["local_language_id"] == ENGLISH_LANG_ID:
sid = int(row["pokemon_species_id"])
genus = row.get("genus", "")
if genus and sid <= MAX_SPECIES_ID:
genus_map[sid] = genus

# Flavor text: species_id -> English flavor text (latest version)
# We pick the entry with the highest version_id for each species
flavor_text_raw = defaultdict(list)
for row in data["pokemon_species_flavor_text.csv"]:
if row["language_id"] == ENGLISH_LANG_ID:
sid = int(row["species_id"])
if sid <= MAX_SPECIES_ID:
version_id = int(row["version_id"])
text = row.get("flavor_text", "")
if text:
flavor_text_raw[sid].append((version_id, text))
flavor_text_map = {}
for sid, entries in flavor_text_raw.items():
# Pick the latest version's text and clean it up
entries.sort(key=lambda x: x[0], reverse=True)
text = entries[0][1]
# PokéAPI flavor text has form feeds and newlines embedded
text = text.replace("\f", " ").replace("\n", " ").replace("\r", " ")
# Collapse multiple spaces
text = " ".join(text.split())
flavor_text_map[sid] = text

# Growth rates: growth_rate_id -> English name
growth_rate_map = {}
for row in data["growth_rate_prose.csv"]:
if row["local_language_id"] == ENGLISH_LANG_ID:
gid = int(row["growth_rate_id"])
growth_rate_map[gid] = row["name"]
# Fallback from growth_rates.csv identifiers
if not growth_rate_map:
for row in data["growth_rates.csv"]:
gid = int(row["id"])
name = " ".join(w.capitalize() for w in row["identifier"].split("-"))
growth_rate_map[gid] = name

# Build the final Pokémon list
print("Building Pokémon entries...\n")

Expand Down Expand Up @@ -433,6 +485,12 @@ def main():
"height": pdata["height"],
"weight": pdata["weight"],
"color": color,
"category": genus_map.get(species_id, ""),
"description": flavor_text_map.get(species_id, ""),
"catchRate": sdata["capture_rate"],
"baseHappiness": sdata["base_happiness"],
"baseExp": pdata["base_experience"],
"growthRate": growth_rate_map.get(sdata["growth_rate_id"], ""),
}

pokemon_list.append(entry)
Expand Down