Vanilla JS "Who's that Pokémon?" game with the PokéAPI

Vanilla JS "Who's that Pokémon?" game with the PokéAPI

Remember that "Who's that Pokémon?" TV game? Well we can build our own version of this with the PokéAPI!

If we make a fetch call to this endpoint (and specify that we want to limit it to the first 151 Pokémon), we'll get a results array:

(async () => {
  const res = await fetch('');
  const json = await res.json();


// Logs:
  {name: 'bulbasaur', url: ''},
  {name: 'ivysaur', url: ''},
  {name: 'venusaur', url: ''},
 // ...

That url property inside each object is the pokémon-specific endpoint that can be hit for more information about that individual character. Inside this JSON, there will be a sprite URL like so:

This is the sprite for Pokémon #1:

Since we saw in the original data that Bulbasaur's url property shows its number (1), and this number is the same that's used in the sprite URL, we can use just this original request to get all the information we need to create a "Who's that Pokémon?" game:

The full code for this project is hosted here, but the rest of this article will show the core components we'll need to make this work.

First, our HTML structure:

<main class="fetching">

  <div id="pokemon-container">
    <img id="pokeball" src="background.jpg">
    <img id="pokemon-image" src="placeholder.png">

  <div id="answer">
    <div id="bg-overlay"></div>
    <div id="text-overlay"></div>

  <section id="controls">
    <button id="play">Play</button>
    <div id="choices"></div>

The #pokemon-image source will be set dynamically to show the featured pokémon, and the #choices element will be populated with multiple-choice answers from the PokéAPI data. The steps to get the need we'll need is as follows:

getPokeData = async function() {
  const pokemon = await getPokemon(); // #1
  const randomPokemon = shuffle(pokemon); // #2
  const pokemonChoices = get4Pokemon(randomPokemon); // #3
  const [ firstPokemon ] = pokemonChoices; // #4
  const image = getPokemonImage(firstPokemon); // # 5

  return { 
    pokemonChoices: shuffle(pokemonChoices),
    correct: {

1) Fetch the array of 151 Pokémon objects (show above).

2) Shuffle the array show we can show a random group to the user:

function shuffle(unshuffled) {
  const shuffled = unshuffled
    .map((value) => ({ value, sort: Math.random() }))
    .sort((a, b) => a.sort - b.sort)
    .map(({ value }) => value);

  return shuffled;

3) Save the first 4 objects from this shuffled array:

function get4Pokemon(randomPokemon) {
  return randomPokemon.splice(0, 4);

4) Save a reference to the first Pokémon object (the one we'll feature).

5) Return an object containing the 4 Pokémon choices (shuffled again), and a "correct" object, containing both the name of the featured pokémon and the image URL to show:

function getPokemonImage({ url }) {
  const number = getNumber(url);
  return `` +

function getNumber(url) {
  const numberRegEx = /(\d+)\/$/;
  return (url.match(numberRegEx) || [])[1];

We'll then plug this URL source into our <img id="pokemon-image"> element and set the brightness of the PNG to 0 with CSS:

#pokemon-image {
  transform: scale(2.5);
  filter: brightness(0);
  transition: filter .5s ease-out;

And generate our #choices content with answer buttons:

const { pokemonChoices } = gameData;
const choicesHTML ={ name }) => {
  return `<button data-name="${name}">${name}</button>`;

choices.innerHTML = choicesHTML;

Once we hook up some additional event handlers and logic to check if the selected matches the correct pokémon, we can toggle some classes to reveal both the right answers and show the full-color pokémon image!

Project code available here:

Full YouTube Tutorial:

Yo! I post byte-sized tips like these often. Follow me if you crave more! 🍿

I'm on TikTok, Twitter and I have a new debugging course dropping soon!