Pokédex

A Flutter Pokédex built around search, rich Pokémon profiles, and evolution families reconstructed from PokéAPI data as interactive graphs.

Cristian De La Hoz

Listen to this story British English · Lewis · 6 min

A Pokédex meant to be explored #

This college project started as a way to learn Flutter against a real public data source. It became a mobile-first browser Pokédex: search by name or number, filter and sort the list, save favorites, play trivia, and open a Pokémon profile without losing the context of the search.

The detail page is the center of the application. About presents identity, biology, abilities, forms, and the complete evolution family. Stats compares base stats and type effectiveness. Moves follows the selected game version. Other collects encounter locations and additional data. The clip below follows that path with Eevee, whose eight branches make it a useful stress test for the evolution layout.

Demo

Navigation diagram #

Excalidraw navigation flow for every main destination and detail-page control

PokéAPI stores a family tree, not a linear evolution chain #

PokéAPI’s REST model represents an evolution chain as a recursive tree. A chain has a root ChainLink; every link contains one species, the conditions under which it reached that stage in evolution_details, and zero or more children in evolves_to. A linear family is simply a tree with one child per level. Eevee is the revealing case: one Eevee link fans out into Vaporeon, Jolteon, Flareon, Espeon, Umbreon, Leafeon, Glaceon, and Sylveon.

Those branches are not interchangeable labels. Evolution details encode the trigger and its constraints: level, item, time of day, happiness, affection, known move or move type, location, weather, party state, trade conditions, and more. The official PokéAPI evolution documentation describes that recursive contract.

This app queries PokéAPI’s GraphQL data instead. The same family arrives as a normalized collection of species. Each record has an id and an evolves_from_species_id; evolution rows carry trigger, item, level, happiness, affection, time, and location. The domain model indexes those records as parent id → children, which restores the tree without assuming that every family has exactly three stages.

graphql
evolutionchain {
  id
  pokemonspecies(order_by: {id: asc}) {
    id
    name
    evolves_from_species_id
    pokemonevolutions {
      min_level
      min_happiness
      min_affection
      time_of_day
      evolutiontrigger { name }
      item { name }
      location { id }
    }
  }
}

How to create the evolution graph #

The graph renderer does not hard-code Bulbasaur’s three stages or Eevee’s eight outcomes. It creates one node per species, then creates a directed edge from the parent identified by evolvesFromSpeciesId to that species. GraphView receives the resulting tree and the Sugiyama algorithm assigns levels and minimizes crossings. Families with more than two siblings switch to a left-to-right orientation so broad branches use the screen more effectively; smaller families remain top-to-bottom.

dart
final graph = Graph()..isTree = true;
final nodes = <int, Node>{};

for (final species in chain.species) {
  final node = Node.Id(species.speciesId);
  nodes[species.speciesId] = node;
  graph.addNode(node);
}

for (final species in chain.species) {
  final parent = nodes[species.evolvesFromSpeciesId];
  final child = nodes[species.speciesId];
  if (parent != null && child != null) graph.addEdge(parent, child);
}

final configuration = SugiyamaConfiguration()
  ..nodeSeparation = 40
  ..levelSeparation = 70
  ..orientation = maxVerticalNodes > 2
      ? SugiyamaConfiguration.ORIENTATION_LEFT_RIGHT
      : SugiyamaConfiguration.ORIENTATION_TOP_BOTTOM;

return GraphView.builder(
  graph: graph,
  algorithm: SugiyamaAlgorithm(configuration),
  autoZoomToFit: true,
  builder: (Node node) => EvolutionSpeciesCard(
    species: speciesMap[node.key!.value as int]!,
  ),
);
Eevee and its branching evolution graph in the running application

Something I did not expect, as someone who did not know much about Pokémon, was that evolutions are not always linear. Eevee’s evolution family forms a tree, so I had to design a branching graph, attach each species to its parent, and let the layout algorithm arrange the resulting levels.

Make yourself at home

Text size
100%
75%125%
Appearance
Language