Intro
After finishing up my DS project, I was looking for something fun to work on next and kept coming back to Pokémon. The whole idea actually started when I was looking for a new profile picture and found a Latios one from Mystery Dungeon. I figured there are probably some people out there also wishing a database existed where they could get a new PFP of their favorite Pokémon easily.
* * *
The Home Page
The first thing you see when you open myst.so is five randomly selected portraits animated onto the homepage. Each card has a unique rotation and a vertical offset, so the stack feels natural. They are also slightly staggered so that each card animates in one after another.
Hovering pushes the neighboring cards outward to give it room, and a small tooltip appears above with the number, name, and mood. Clicking on a card plays a transition where the portrait expands from its position on the homepage directly into the Pokédex page. This makes it feel like you're opening the card rather than navigating to a new URL, even though the URL is changing.
The first version tried to fit everything onto a single page: the randomizer, Pokédex, and homepage all at once. It became too cluttered, so I separated them into three pages. Each page also gets its own toolbar with icons that have a small interaction on hover, which gives each one a bit of personality.
Bulk Export
A common request after the first version was the ability to export multiple portraits at once. Now you can make multiple selections and download them as a zip. JSZip bundles everything client-side and downloads a .zip with all the portraits at the selected resolution.
The Collection
The portraits are all stored locally in the public folder, organized by:
- Generation (1-9)
- Type (Fire, Water, Grass, etc.)
- Mood (Happy, Serious, Cute, etc.)
- Shiny variants
- Special forms (like Deoxys, Castform, Rotom, etc.)
And each Pokémon has its own folder, organized by its National Dex number:
public/portrait/
0001/ (Bulbasaur)
0001_happy.png
0001_serious.png
_shiny/
0001_happy.png
0001_serious.png
0002/ (Ivysaur)Each portrait is 40×40, or about 1KB. Scaling them up with standard browser interpolation blurred them a lot. Setting image-rendering to pixelated tells the browser to use nearest-neighbor scaling instead, so portraits can scale to whatever size we want. Users can select between three export sizes: small at 128×128 (great for Discord emojis, Slack, or similar), medium at 500px, and large at 1000px.

Branding
V1 had no special branding, so I wanted to include something in the new refresh that felt playful and drew inspiration from actual items in the game. The main logo uses a Munchlax Belt and the changelog uses an Energy Seed. I made both in Figma and it was a lot of fun going through all the different variations. I couldn't fit a custom logo onto the Pokédex and roll pages, but I'm actively looking at ways to do that. Creating a unique logo per page makes each one feel distinct while still part of the same project. The ::selection color on each page also matches the icon in the nav bar.
Credits
All of the pixel art sprites featured in myst.so come from the wonderful artists at PMD Collab. This app serves as a random generator that showcases their incredible work. I just wanted to build something that made all of these portraits more accessible to people. 🙂
For artist credits, each portrait links directly back to the original sprite in the PMD Collab database. The URL generation dynamically updates the link based on the national Pokedex number:
href={`https://sprites.pmdcollab.org/#/${portraitInfo.dexNumber
.toString()
.padStart(4, 0)}`}
target=_blank
rel=noopener noreferrer
className="flex items-center gap-1 underline"The dexNumber is converted to a string and padded with leading zeros to make it a 4-digit number (like 0001, 0380, 0493, etc.), so clicking on Latios's credit will take you directly to https://sprites.pmdcollab.org/#/0381 in the original database.
myst.so might be a niche little web app with 5 monthly users (hopefully more!), but even a small project is worth building with care.