Random Shiny Pokémon Generator | Fast & Free

Your shiny Pokémon will appear here!

`; } } function showLoading() { outputDiv.innerHTML = '
'; randomGenerateBtn.disabled = true; filteredGenerateBtn.disabled = true; } function hideLoading() { randomGenerateBtn.disabled = false; filteredGenerateBtn.disabled = false; } // --- MODIFIED RENDER RESULTS FUNCTION --- function renderResults(pokemonList) { outputDiv.innerHTML = ''; // Clear previous results or placeholders if (!pokemonList || pokemonList.length === 0) { outputDiv.innerHTML = `

No Pokémon found matching your criteria. Try different filters!

`; return; } const scrollWrapper = document.createElement('div'); scrollWrapper.className = 'spg-scroll-wrapper'; const resultsContainer = document.createElement('div'); resultsContainer.className = 'spg-results-container'; pokemonList.forEach(pokemon => { const card = document.createElement('div'); card.className = 'spg-poke-card'; const name = pokemon.name; const spriteName = name.toLowerCase().replace(/[\s'.]/g, "").replace('♀', '-f').replace('♂', '-m'); const img = document.createElement('img'); img.src = POKE_SPRITE_URL.replace('{name}', spriteName); img.alt = `Shiny ${capitalize(name)}`; img.onerror = function() { this.onerror = null; this.src = `https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/shiny/${pokemon.id}.png`; this.style.imageRendering = 'auto'; this.onerror = function() { this.onerror = null; this.src = 'https://placehold.co/120x120/e9ecef/6c757d?text=?'; this.alt = 'Image not found'; } }; const nameEl = document.createElement('p'); nameEl.textContent = capitalize(name); card.appendChild(img); card.appendChild(nameEl); resultsContainer.appendChild(card); }); // Add scroll buttons const leftBtn = document.createElement('button'); leftBtn.className = 'spg-scroll-btn spg-scroll-btn-left'; leftBtn.innerHTML = ``; const rightBtn = document.createElement('button'); rightBtn.className = 'spg-scroll-btn spg-scroll-btn-right'; rightBtn.innerHTML = ``; scrollWrapper.appendChild(leftBtn); scrollWrapper.appendChild(resultsContainer); scrollWrapper.appendChild(rightBtn); outputDiv.appendChild(scrollWrapper); // Scroll button logic const updateScrollButtons = () => { const hasOverflow = resultsContainer.scrollWidth > resultsContainer.clientWidth; if (!hasOverflow) { leftBtn.classList.remove('visible'); rightBtn.classList.remove('visible'); return; } // Check left edge leftBtn.classList.toggle('visible', resultsContainer.scrollLeft > 0); // Check right edge (with a small tolerance) rightBtn.classList.toggle('visible', resultsContainer.scrollLeft < resultsContainer.scrollWidth - resultsContainer.clientWidth - 1); }; leftBtn.addEventListener('click', () => { resultsContainer.scrollLeft -= resultsContainer.clientWidth * 0.7; }); rightBtn.addEventListener('click', () => { resultsContainer.scrollLeft += resultsContainer.clientWidth * 0.7; }); resultsContainer.addEventListener('scroll', updateScrollButtons, { passive: true }); // Use a timeout to ensure layout is calculated before checking for overflow setTimeout(updateScrollButtons, 100); } async function getFullPokemonList() { if (allPokemonList.length > 0) return allPokemonList; const data = await cachedFetch(`${API_BASE}pokemon?limit=1302`); allPokemonList = data.results; return allPokemonList; } async function handleGenerate(mode) { showLoading(); try { let count, potentialPokemon; if (mode === 'random') { count = parseInt(randomCountSelect.value, 10); const allPokes = await getFullPokemonList(); potentialPokemon = [...allPokes]; } else { count = parseInt(filterCountSelect.value, 10); potentialPokemon = await getFilteredPokemon(); } if (potentialPokemon.length === 0) { renderResults([]); return; } const selectedPokemon = []; const fetchedDetails = new Map(); while (selectedPokemon.length < count && potentialPokemon.length > 0) { const index = Math.floor(Math.random() * potentialPokemon.length); const chosen = potentialPokemon.splice(index, 1)[0]; if (!fetchedDetails.has(chosen.url)) { const details = await cachedFetch(chosen.url); fetchedDetails.set(chosen.url, details); } const fullDetails = fetchedDetails.get(chosen.url); selectedPokemon.push({name: chosen.name, id: fullDetails.id}); } renderResults(selectedPokemon); } catch (error) { console.error("Generation failed:", error); outputDiv.innerHTML = `

An error occurred. Please try again.

`; } finally { hideLoading(); } } async function getFilteredPokemon() { const gen = genSelect.value; const type = typeSelect.value; const evolution = evolutionSelect.value; let listsToIntersect = []; if (gen !== 'any') { const data = await cachedFetch(`${API_BASE}generation/${gen}`); listsToIntersect.push(data.pokemon_species.map(p => p.name)); } if (type !== 'any') { const data = await cachedFetch(`${API_BASE}type/${type}`); listsToIntersect.push(data.pokemon.map(p => p.pokemon.name)); } let filteredList; if (listsToIntersect.length > 0) { filteredList = listsToIntersect.reduce((a, b) => a.filter(c => b.includes(c))); } else { const allPokes = await getFullPokemonList(); filteredList = allPokes.map(p => p.name); } let pokemonObjects = filteredList.map(name => ({ name, url: `${API_BASE}pokemon/${name}` })); if (evolution !== 'any') { const evolutionFiltered = []; for (const pokemon of pokemonObjects) { try { const speciesData = await cachedFetch(`${API_BASE}pokemon-species/${pokemon.name.split('-')[0]}/`); const isBase = speciesData.evolves_from_species === null; if (evolution === 'base' && isBase) { evolutionFiltered.push(pokemon); continue; } if (evolution === 'final') { const evolutionChainData = await cachedFetch(speciesData.evolution_chain.url); let chain = evolutionChainData.chain; let isFinal = false; while(chain) { if (chain.species.name === pokemon.name && chain.evolves_to.length === 0) { isFinal = true; break; } if (chain.evolves_to.length > 0) { let foundInNext = false; for (const next of chain.evolves_to) { if (next.species.name === pokemon.name && next.evolves_to.length === 0) { isFinal = true; foundInNext = true; break; } } if (foundInNext) break; chain = chain.evolves_to[0]; } else { chain = null; } } if(isFinal) evolutionFiltered.push(pokemon); } } catch (e) { /* Ignore failures */ } } return evolutionFiltered; } return pokemonObjects; } // --- Event Listeners --- randomGenerateBtn.addEventListener('click', () => handleGenerate('random')); filteredGenerateBtn.addEventListener('click', () => handleGenerate('filtered')); // --- Initializer Call --- setupTabs(); populateFilters(); } })();

Other Random Generators

Generator Modes Overview

Random Mode

Random mode picks shiny Pokémon for you randomly. You only select how many Pokémon you want, then click generate. This mode works best when you want fast results and full surprise.

Beginners love this option because it removes every decision. The tool handles everything while you enjoy the shiny reveal. One click gives you instant results.

Filtered Mode

Filtered mode lets you guide the randomness without making things complicated. You choose simple options like generation, type, or evolution stage. The tool still picks shiny Pokémon randomly within your choices.

This mode helps users who want themed teams but still want surprise.

After discovering a random shiny, use our random Pokémon team building generators to see which partners complement it best.

Customization Options

Team Size Control

You can choose to generate between one and six shiny Pokémon. A single Pokémon works great for quick fun, while six creates a full team. The tool adjusts instantly when you change the number.

Generation Filter

The generation filter limits results to a specific Pokémon era. This helps if you like older or newer Pokémon styles. Leaving it on any gives you full randomness.

Type Filter

The type filter groups Pokémon by elements like fire or water. This option helps create themed shiny teams easily. You can skip it if you want full variety.

Evolution Stage Filter

The evolution stage filter lets you pick base forms, final forms, or both. Beginners often choose final forms because they look stronger.

How the Generator Works

Random Selection Logic

The tool pulls real Pokémon data and selects results randomly. Every click creates a fresh outcome. No preset lists control your results.

Shiny Sprite Rendering

Each result shows a shiny Pokémon image immediately. Animated shiny sprites appear when available.

Duplicate Prevention

The generator avoids repeating the same Pokémon in one result. Every team feels unique and complete. This keeps results exciting.

Ease of Use

No Account Required

You use the tool instantly without signing up. No emails or passwords slow you down. Everything works right away.

Works on All Devices

The generator works on phones, tablets, and computers. Buttons stay clear and readable everywhere. You can generate anytime.

Beginner Friendly

You do not need Pokémon knowledge to use this tool. Labels explain every option clearly. The generator does the hard work.