POKEDEX

JAVAFX DEVELOPER DOCUMENTATION

Project Overview

A retro-styled Pokédex application built with JavaFX, featuring pixel-perfect UI positioning, JSON data loading, sound effects, and an authentic Pokémon lookup experience.

MVC Architecture JavaFX 21 Jackson JSON Java 21
✨ Key Features
  • Browse all 151 original Kanto Pokémon
  • Reveal/Hide toggle for mystery mode
  • Power on/off functionality
  • Navigate with previous/next buttons
  • Detailed Pokémon information display
  • Silhouette effect for hidden Pokémon
  • Authentic retro pixel art style
  • "Who's That Pokemon?" sound effect
🎯 Learning Objectives
  • MVC pattern implementation
  • JavaFX custom UI design
  • JSON data parsing with Jackson
  • Resource management (images, fonts, audio)
  • Event-driven programming
  • State management patterns
  • Java Module System (JPMS)
  • Media playback with JavaFX
🔧 Technical Stack
Technology Version Purpose
Java 21 Core programming language
JavaFX 21 UI framework for desktop application
JavaFX Media 21 Audio playback for sound effects
Jackson 2.15.2 JSON parsing and data binding
Maven 3.x Build automation and dependency management

Architecture

MVC Design Pattern

This application follows the Model-View-Controller architectural pattern, ensuring clean separation of concerns, maintainability, and testability. Each component has a distinct responsibility with well-defined interfaces between layers.

📦 Model Layer

Package: com.example.model

File: PokedexModel.java

Responsibilities:

  • Manages application state and business logic
  • Loads and stores Pokémon data from JSON
  • Handles navigation (next/previous)
  • Manages reveal/hide state
  • Tracks power on/off state
  • Provides data access methods
  • Wraps around boundaries (first ↔ last)

Key Methods:

  • loadData() - JSON parsing
  • nextPokemon() - Navigate forward
  • previousPokemon() - Navigate backward
  • toggleReveal() - Toggle display mode
  • getCurrentPokemon() - Get active Pokémon
  • powerOn() / powerOff() - State control
🎨 View Layer

Package: com.example.view

File: PokedexView.java

Responsibilities:

  • Renders the user interface
  • Displays Pokémon information and sprites
  • Creates interactive button hitboxes
  • Applies visual effects (silhouettes)
  • Manages layout and positioning
  • Loads fonts and background images
  • Plays sound effects
  • Updates UI based on model state

UI Components:

  • Background image (pokedex_bg.png)
  • Pokémon sprite display (ImageView)
  • Name, description, types labels
  • Dex number display
  • Interactive button rectangles
  • Custom pixel font (Press Start 2P)
  • MediaPlayer for sound effects
🎮 Controller Layer

Package: com.example.controller

File: PokedexController.java

Responsibilities:

  • Bridges Model and View
  • Handles user input events
  • Updates View when Model changes
  • Coordinates application flow
  • Enforces business rules (e.g., powered-on requirement)
  • Manages button click handlers
  • Loads Pokemon data at startup

Event Handlers:

  • handlePowerOn() - Activates the Pokédex
  • handlePowerOff() - Deactivates the Pokédex
  • handleNextPokemon() - Shows next Pokémon
  • handlePreviousPokemon() - Shows previous Pokémon
  • handleToggleReveal() - Toggles mystery mode
  • updateDisplay() - Refreshes display
📊 Data Flow Diagram
USER INTERACTION
Button Clicks on View Layer
Events
CONTROLLER
Event Handlers
Manages event flow and coordinates between layers
Updates UI
VIEW
UI Rendering
Displays components and layouts
Loads
RESOURCES
Images, Fonts & Audio
Queries State
MODEL
Data & Logic
Manages application state
Loads
JSON DATA
Pokemon Information
🔄 State Management

The application maintains several state variables in the Model:

State Variable Type Purpose
currentIndex int Currently displayed Pokémon position
isRevealed boolean Whether Pokémon details are visible
isPoweredOn boolean Whether the Pokédex is active
pokedexList List<Pokemon> All loaded Pokémon data
Important: All interactive actions (navigation, toggle) are blocked when isPoweredOn == false. This simulates a real device that must be powered on to function.

Core Components

Pokemon.java - Data Model

Represents a single Pokémon with all its attributes. This POJO (Plain Old Java Object) is used by Jackson for JSON deserialization.

package com.example.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.List;

public class Pokemon {
    private String picture;          // Filename of sprite image
    private String name;             // Pokémon name
    private int evolutionStage;      // 1, 2, or 3
    private String shortDescription; // Brief description
    private int dexNumber;           // National Pokédex number
    
    @JsonProperty("isLegendary")
    private boolean legendary;       // Legendary status
    
    private List<String> types;      // e.g., ["Fire", "Flying"]
    
    // Getters and setters for all fields
}
Jackson Annotations: The @JsonProperty("isLegendary") annotation maps the JSON field "isLegendary" to the boolean field "legendary". All other fields use automatic mapping since they match JSON keys exactly.
App.java - Application Entry Point

The main class that extends Application and initializes the MVC components. It sets up the Scene and Stage, then delegates control to the Controller.

package com.example;

import com.example.controller.PokedexController;
import com.example.model.PokedexModel;
import com.example.view.PokedexView;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class App extends Application {
    @Override
    public void start(Stage stage) {
        // Initialize MVC components
        PokedexModel model = new PokedexModel();
        PokedexView view = new PokedexView(getClass());
        PokedexController controller = 
            new PokedexController(model, view, getClass());
        
        // Load data
        controller.loadData();
        
        // Create scene
        Scene scene = new Scene(
            view.getRoot(), 
            PokedexView.getWindowWidth(), 
            PokedexView.getWindowHeight()
        );
        
        // Setup stage
        stage.setTitle("Pokédex");
        stage.setScene(scene);
        stage.setResizable(false);
        stage.show();
        
        // Initialize to powered off state
        controller.initializePoweredOff();
    }
    
    public static void main(String[] args) {
        launch(args);
    }
}
Resource Loading Pattern

The application uses Class.getResourceAsStream() to load resources, ensuring they work correctly whether running from IDE or JAR file. The Class object is passed to the View and Controller for resource access.

// In View constructor - passed from App
public PokedexView(Class resourceClass) {
    this.resourceClass = resourceClass;
    // ... initialization
}

// Loading an image
String imgPath = "/pokedex/pokemon-pictures/1.png";
InputStream stream = resourceClass.getResourceAsStream(imgPath);
if (stream != null) {
    Image image = new Image(stream);
    imageView.setImage(image);
}

// Loading font
InputStream fontStream = resourceClass
    .getResourceAsStream("/fonts/PressStart2P-Regular.ttf");
Font customFont = Font.loadFont(fontStream, 12);

// Loading audio
String audioPath = resourceClass
    .getResource("/whos-that-pokemon.mp3").toExternalForm();
Media media = new Media(audioPath);
MediaPlayer player = new MediaPlayer(media);
Always check for null! If a resource is not found, getResourceAsStream() returns null. Always validate before using to avoid NullPointerException.
JSON Data Loading

Jackson ObjectMapper handles the deserialization of JSON data into Java objects. The Model uses this to populate the Pokémon list at startup.

public boolean loadData(InputStream inputStream) {
    ObjectMapper mapper = new ObjectMapper();
    try {
        if (inputStream == null) {
            return false;
        }
        
        // Deserialize JSON array into List<Pokemon>
        pokedexList = mapper.readValue(
            inputStream,
            new TypeReference<List<Pokemon>>() {}
        );
        
        return !pokedexList.isEmpty();
    } catch (IOException e) {
        e.printStackTrace();
        return false;
    }
}
UI Positioning System

All UI elements use absolute positioning relative to the background image. Constants define each component's exact location to ensure pixel-perfect alignment.

// View class constants
private static final double WIN_W = 548;
private static final double WIN_H = 400;
private static final double SCREEN_X = 128, SCREEN_Y = 125;
private static final double SCREEN_W = 104, SCREEN_H = 104;

private static final double POKEMON_NUMBER_X = 79;
private static final double POKEMON_NUMBER_Y = 140;

private static final double DESC_X = 77, DESC_Y = 314;
private static final double DESC_W = 111, DESC_H = 43;
Design Principle: This approach trades flexibility for precision. The UI perfectly matches the background image design, creating an authentic retro device experience.
Silhouette Effect Implementation

When in mystery mode (isRevealed = false), the Pokémon sprite is shown as a black silhouette using JavaFX's ColorAdjust effect.

// Create the effect (in View constructor)
silhouetteEffect = new ColorAdjust();
silhouetteEffect.setBrightness(-1.0);  // Maximum darkness

// Apply to ImageView (in displayPokemonHidden)
if (!model.isRevealed()) {
    mainScreenImage.setEffect(silhouetteEffect);
} else {
    mainScreenImage.setEffect(null);  // Clear effect
}
🔊 Sound Effect Implementation (NEW!)

The application plays a "Who's That Pokemon?" sound effect when entering mystery mode. This enhances the authentic Pokemon experience.

// MediaPlayer field in View class
private MediaPlayer mediaPlayer;

// Play sound when displaying hidden Pokemon
private void playWhosThatPokemonSound() {
    try {
        // Stop existing sound if playing
        if (mediaPlayer != null) {
            mediaPlayer.stop();
        }
        
        // Load and play sound
        String path = resourceClass
            .getResource("/whos-that-pokemon.mp3")
            .toExternalForm();
        Media media = new Media(path);
        mediaPlayer = new MediaPlayer(media);
        mediaPlayer.play();
    } catch (Exception e) {
        System.err.println("Could not play sound: " + e.getMessage());
    }
}

// Called from displayPokemonHidden method
public void displayPokemonHidden(Pokemon pokemon, boolean isPoweredOn) {
    if (pokemon == null) return;
    
    // Play sound effect
    if (isPoweredOn) {
        playWhosThatPokemonSound();
    }
    
    // Apply silhouette and update UI
    // ...
}
Module Requirement: To use JavaFX Media, you must add requires javafx.media; to your module-info.java file and include the javafx-media dependency in pom.xml.

Project Structure

📁 Directory Layout
  • 📁 demo
    • 📂 src
      • 📁 main
        • 📁 java
          • 📁 com.example
            • J App.java
            • 📁 controller
              • J PokedexController.java
            • 📁 model
              • J PokedexModel.java
              • J Pokemon.java
            • 📁 view
              • J PokedexView.java
          • J module-info.java
        • 📁 resources
          • 🖼 pokedex_bg.png
          • whos-that-pokemon.mp3
          • 📁 pokedex
            • {} kanto_pokemon.json
            • 📁 pokemon-pictures
              • 🖼 1.png
              • 🖼 2.png
              • ... (more sprites)
              • (151 Pokemon images total)
          • 📁 fonts
            • 🔤 PressStart2P-Regular.ttf
    • <> pom.xml
    • M README.md
Key Structure Notes:
  • Pokemon images are in /pokedex/pokemon-pictures/ subdirectory
  • Background image is at root resources level: /pokedex_bg.png
  • Sound effect is at root resources level: /whos-that-pokemon.mp3
  • MVC packages are separated: controller, model, view
⚙️ Installation & Setup

Prerequisites:

  • Java 21 or higher (JDK)
  • Maven 3.6 or higher
  • Git (for cloning)

Step 1: Clone Repository

git clone <repository-url>
cd demo

Step 2: Build Project

mvn clean install

Step 3: Run Application

mvn javafx:run
Module System Note: Ensure your module-info.java properly exports packages and opens the model package to Jackson for reflection:
module com.example {
    // JavaFX dependencies
    requires javafx.controls;
    requires javafx.graphics;
    requires javafx.media;        // Required for sound effects
    requires javafx.fxml;
    
    // Jackson dependencies
    requires com.fasterxml.jackson.databind;
    requires com.fasterxml.jackson.core;
    requires com.fasterxml.jackson.annotation;
    
    // Export packages
    exports com.example;
    exports com.example.controller;
    exports com.example.view;
    exports com.example.model;
    
    // Open for reflection (Jackson)
    opens com.example.model to com.fasterxml.jackson.databind;
}
Maven Configuration (pom.xml)

Key sections of the Maven configuration:

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>21</maven.compiler.source>
    <maven.compiler.target>21</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-controls</artifactId>
        <version>21</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-fxml</artifactId>
        <version>21</version>
    </dependency>
    <dependency>
        <groupId>org.openjfx</groupId>
        <artifactId>javafx-media</artifactId>
        <version>21</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-maven-plugin</artifactId>
            <version>0.0.8</version>
            <executions>
                <execution>
                    <id>default-cli</id>
                    <configuration>
                        <mainClass>com.example.App</mainClass>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Data Structure

JSON Format (kanto_pokemon.json)

The Pokémon data is stored in a JSON array. Each entry follows this structure:

[
  {
    "picture": "pokemon-pictures/1.png",
    "name": "bulbasaur",
    "evolutionStage": 1,
    "shortDescription": "A strange seed was planted on its back at birth...",
    "dexNumber": 1,
    "isLegendary": false,
    "types": ["grass", "poison"]
  },
  {
    "picture": "pokemon-pictures/2.png",
    "name": "ivysaur",
    "evolutionStage": 2,
    "shortDescription": "When the bulb on its back grows large...",
    "dexNumber": 2,
    "isLegendary": false,
    "types": ["grass", "poison"]
  }
]
Image Path Structure: Note that the "picture" field includes the subdirectory path "pokemon-pictures/". The View prepends "/pokedex/" to create the full resource path: "/pokedex/pokemon-pictures/1.png"
Field Descriptions
Field Type Description
picture String Relative path to sprite (e.g., "pokemon-pictures/1.png")
name String Pokémon name (displayed prominently)
evolutionStage Integer Evolution stage: 1 (basic), 2 (stage 1), 3 (stage 2)
shortDescription String Brief description shown in the Pokédex screen
dexNumber Integer National Pokédex number (1-151 for Kanto)
isLegendary Boolean Whether the Pokémon is legendary
types Array[String] Pokémon types (e.g., ["fire"], ["water", "flying"])
Data Validation Rules
  • Picture field: Must be a relative path from /pokedex/ directory (includes "pokemon-pictures/" subdirectory)
  • Evolution stage: Must be 1, 2, or 3 (no other values)
  • Dex number: Should be unique and sequential for Kanto (1-151)
  • Types: Can have 1 or 2 types (no Pokémon has zero types)
  • Short description: Should be brief enough to fit in the display area
Tip: Keep descriptions under 150 characters to ensure they fit properly in the UI. The font and text wrapping are configured for concise entries.
Example Pokemon Types
Pokémon Types Type Combination
Bulbasaur grass, poison Dual-type
Charmander fire Single-type
Gyarados water, flying Dual-type
Zapdos electric, flying Dual-type, Legendary

UI System

The UI uses pixel-perfect absolute positioning relative to the background image. Each component is carefully aligned to create an authentic retro Pokédex experience.

📺 Display Coordinates
Component X, Y Position Dimensions
Window - 548 × 400 px
Pokémon Screen 128, 125 104 × 104 px
Dex Number 79, 140 Auto-sized
Description 77, 314 111 × 43 px
Details Labels 337, 128 (starts) Auto-sized
🎮 Button Hitboxes
Button X, Y Position Size (W×H) Function
Reveal/Hide 30, 272 37 × 37 px Toggle Mode
Power On 127.72, 14.34 16 × 16 px Boot Device
Power Off 84.65, 14.34 16 × 16 px Shutdown
Navigate Left 205, 309 17 × 17 px Previous
Navigate Right 244, 309 17 × 17 px Next
Implementation Note: Buttons are created as transparent Button objects with opacity set to 0. They are positioned precisely over the background button graphics.
🎨 Visual Styling
  • Font: Press Start 2P - Authentic retro pixel font for that classic 8-bit feel
  • Text Colors:
    • Standard text: #000000 (Black)
    • Mystery mode: #C42020FF (Red)
    • Description: #084036 (Dark green)
    • Digital display: #32EE25 (Bright green)
  • Silhouette Effect: ColorAdjust effect with brightness set to -1.0 creates perfect black silhouettes
  • Text Wrapping: Description text wraps at 111px width to fit the screen area
  • Font Sizes: Carefully calibrated for readability (6-12px depending on component)
Layout Implementation Details

The View class uses a Pane as the root container, allowing absolute positioning of all children. Key implementation points:

// Root container setup
root = new Pane();

// Background image
ImageView background = new ImageView(
    new Image(resourceClass.getResourceAsStream("/pokedex_bg.png"))
);
background.setFitWidth(WIN_W);
background.setFitHeight(WIN_H);
root.getChildren().add(background);

// Positioned components
mainScreenImage.setLayoutX(SCREEN_X);
mainScreenImage.setLayoutY(SCREEN_Y);
mainScreenImage.setFitWidth(SCREEN_W);
mainScreenImage.setFitHeight(SCREEN_H);

pokemonNumberLabel.setLayoutX(POKEMON_NUMBER_X);
pokemonNumberLabel.setLayoutY(POKEMON_NUMBER_Y);
Responsive Behavior

Current Implementation: Fixed window size (548×400) for pixel-perfect display matching the background image.

Why Fixed Size? This ensures the UI remains aligned with the background graphics. Resizing would require dynamic scaling of all positioned elements, which would compromise the authentic retro aesthetic.

Extension Opportunity: For a responsive version, you could:

  • Scale all coordinates proportionally to window size
  • Use percentage-based positioning
  • Implement SVG graphics instead of PNG for scaling
  • Add multiple layout profiles for different screen sizes

Development Workflow

Adding New Pokemon
  1. Prepare the sprite image: Ensure it's a PNG file with transparent background, sized appropriately (square recommended)
  2. Add image to resources: Place the file in src/main/resources/pokedex/pokemon-pictures/ with number as filename (e.g., "152.png")
  3. Update JSON data: Add a new entry to kanto_pokemon.json with all required fields
  4. Verify filename match: Ensure the picture field in JSON matches: "pokemon-pictures/152.png"
  5. Rebuild project: Run mvn clean install
  6. Test: Run the application and navigate to the new Pokémon to verify display
Modifying UI Layout
  1. Locate constants: Open PokedexView.java and find the positioning constants at the top
  2. Adjust coordinates: Modify SCREEN_X, SCREEN_Y, or other position/size constants as needed
  3. Recompile and test: Run the application to verify positioning looks correct
  4. Update button hitboxes: If buttons no longer align with graphics, adjust their coordinates
  5. Consider background changes: If modifying the background image, update all dependent coordinates accordingly
Pro Tip: Use graphic editing software to measure exact pixel coordinates on the background image before updating constants.
Adding New Features

Follow the MVC pattern:

  1. Model: Add state variables and business logic methods to PokedexModel.java
  2. View: Add new UI components and positioning in PokedexView.java
  3. Controller: Create event handlers and wire up interactions in PokedexController.java
  4. Test thoroughly: Verify all state transitions work correctly and UI updates properly

Example - Adding a "Favorite" feature:

  • Model: Add Set<Integer> favorites and toggleFavorite() method
  • View: Add a star icon/button and highlight for favorites
  • Controller: Add handleFavoriteToggle() handler and update view to show favorite status
Testing Checklist

Before considering a feature complete, verify the following:

Category Test Cases
Power State
  • Power on/off functionality works correctly
  • Screen clears when powered off
  • All interactions blocked when off
  • Device can be powered back on
Navigation
  • Next button advances to next Pokémon
  • Previous button goes back
  • Navigation wraps at boundaries (151 → 1, 1 → 151)
  • Navigation only works when powered on
Display
  • Images load correctly for all Pokémon
  • Text fits within designated areas
  • Font renders properly (no missing characters)
  • Colors match specification
Reveal/Hide
  • Toggle changes display appropriately
  • Silhouette effect applies/removes correctly
  • Mystery text shows "Who's that Pokemon?"
  • Sound effect plays when hiding (if powered on)
  • State persists during navigation
Sound
  • Sound plays when entering mystery mode
  • Previous sound stops when new one starts
  • No sound when powered off
  • No errors if sound file missing
Data Integrity
  • All 151 Pokémon load successfully
  • No duplicate dex numbers
  • Types display correctly (1-2 types)
  • Descriptions fit in display area
Common Issues & Solutions
Issue Possible Causes Solutions
Images not loading
  • Incorrect resource path
  • File not in resources folder
  • Filename mismatch with JSON
  • Verify files exist in src/main/resources/pokedex/pokemon-pictures/
  • Check filename spelling matches JSON exactly
  • Verify JSON has correct path: "pokemon-pictures/X.png"
  • Rebuild project: mvn clean install
JSON parsing error
  • Invalid JSON syntax
  • Field name mismatch
  • Wrong data type
  • Validate JSON with online validator
  • Ensure field names match Pokemon.java exactly
  • Check data types (string vs number vs boolean)
  • Verify "isLegendary" field is boolean
Sound not playing
  • Sound file missing
  • Incorrect path
  • javafx.media not included
  • Verify MP3 file in resources/ root
  • Check path: "/whos-that-pokemon.mp3"
  • Add javafx-media dependency in pom.xml
  • Add "requires javafx.media;" to module-info.java
Font not displaying
  • Font file missing
  • Incorrect font path
  • Font loading failed silently
  • Verify TTF file in resources/fonts/
  • Check console for font loading errors
  • Use fallback font if load fails
Module errors
  • Missing module declarations
  • Packages not exported
  • Reflection access denied
  • Verify module-info.java requires all dependencies
  • Include javafx.media requirement
  • Export packages used by other modules
  • Open model package to Jackson for reflection
Buttons not working
  • Incorrect hitbox positioning
  • Event handlers not connected
  • Powered-off state blocking actions
  • Adjust button coordinates to match background
  • Verify controller wires up all handlers
  • Check isPoweredOn state
UI misalignment
  • Background image changed
  • Coordinate constants incorrect
  • Window size mismatch
  • Measure exact pixel positions from image
  • Update all relevant constants in View
  • Ensure window size matches background dimensions
Debugging Tips
  • Console Logging: Add System.out.println() statements to track state changes and method calls
  • Resource Loading: Always check if getResourceAsStream() returns null before using the resource
  • State Inspection: Print Model state variables after each interaction to verify correct updates
  • JSON Validation: Use online JSON validators (jsonlint.com) to catch syntax errors
  • Visual Debugging: Temporarily make button hitboxes visible (set opacity to 0.3) to verify positioning
  • Maven Clean: When in doubt, run mvn clean install to ensure fresh build
  • Sound Testing: Check console for MediaPlayer errors if sound doesn't play

Extension Ideas

This project provides an excellent foundation for expanding functionality. Here are some ideas for taking it further, organized by difficulty level and feature category.

🎯 Feature Enhancements
  • Search Functionality: Add a search bar to find Pokémon by name or type
  • Favorite System: Allow users to mark and filter favorite Pokémon
  • Evolution Tree: Visual display of evolution chains with arrows
  • More Sound Effects: Add button click sounds, different cries for each Pokemon
  • Animations: Smooth transitions when navigating between Pokémon
  • Compare Mode: Side-by-side comparison of two Pokémon
  • Type Effectiveness: Show type matchup chart for current Pokémon
  • Multiple Regions: Support for Johto, Hoenn, Sinnoh, etc. with region selector
  • Volume Control: Add slider to adjust sound effect volume
📊 Data Improvements
  • Base Stats: Display HP, Attack, Defense, Special Attack, Special Defense, Speed
  • Stat Visualization: Show stats as radar chart or bar graph
  • Abilities: List Pokémon abilities with descriptions
  • Move Sets: Show learnable moves and level requirements
  • Evolution Requirements: Display level, stone, or trade requirements
  • Catch Information: Include catch rate, locations, and encounter rates
  • Alternate Forms: Support for Mega Evolutions, regional variants, etc.
  • Pokédex Entries: Multiple versions from different games
⚙️ Technical Upgrades
  • Unit Testing: Add JUnit tests for Model and Controller logic
  • External API: Integrate with PokéAPI (pokeapi.co) for live data
  • Data Caching: Cache API responses to reduce network requests
  • User Preferences: Save/load settings and favorites to file
  • Export Functionality: Export Pokémon data to CSV, PDF, or JSON
  • Multi-language: Support for multiple languages (i18n)
  • Responsive Layout: Dynamic sizing for different screen resolutions
  • Offline Mode: Full functionality without internet connection
🎨 UI/UX Enhancements
  • Themes: Multiple color schemes (original, blue, purple, etc.)
  • Animations: Fade transitions, slide effects, sprite animations
  • Keyboard Navigation: Arrow keys and hotkeys for all functions
  • Touch Support: Swipe gestures for navigation on tablets
  • Accessibility: Screen reader support and high contrast mode
  • Custom Backgrounds: Allow users to upload custom Pokédex skins
🎮 Game Features
  • Quiz Mode: "Who's that Pokémon?" guessing game (already has sound effect!)
  • Collection Tracker: Mark which Pokémon you've "caught"
  • Completion Statistics: Track percentage of Pokédex completed
  • Daily Challenge: New Pokémon to identify each day
  • Team Builder: Create and save battle teams
  • Type Coverage: Analyze team type strengths and weaknesses
🔗 Integration Ideas
  • Database: Store data in SQLite or H2 for better performance
  • Cloud Sync: Sync favorites and progress across devices
  • Social Features: Share favorite teams or collections
  • Import from Games: Read save data from Pokémon game files
Implementation Difficulty Guide
Difficulty Example Features Estimated Time
Easy Favorite marking, keyboard shortcuts, themes, additional data fields, volume control 2-5 hours
Medium Search functionality, stat visualization, more sound effects, animations, export to file 1-3 days
Hard API integration, database implementation, evolution tree visualization, quiz mode 1-2 weeks
Advanced Cloud sync, multi-user features, responsive layout, full accessibility 2-4 weeks

Dependencies

Maven Dependencies (pom.xml)
Dependency Version Purpose
org.openjfx:javafx-controls 21 Core JavaFX UI controls (Scene, Stage, Node hierarchy)
org.openjfx:javafx-fxml 21 FXML support (included but not currently used)
org.openjfx:javafx-media 21 Media playback support (MediaPlayer, Media) for sound effects
com.fasterxml.jackson.core:jackson-databind 2.15.2 JSON parsing and data binding - converts JSON to Java objects
Dependency Details

JavaFX 21

Modern UI toolkit for Java desktop applications. Provides rich graphics, media, and UI controls. Requires explicit module declaration in Java 9+.

Key Components Used:

  • javafx.application.Application - Application lifecycle
  • javafx.scene.Scene - Scene graph container
  • javafx.scene.layout.Pane - Layout container
  • javafx.scene.control.Label - Text display
  • javafx.scene.control.Button - Interactive buttons
  • javafx.scene.image.ImageView - Image rendering
  • javafx.scene.effect.ColorAdjust - Visual effects
  • javafx.scene.media.MediaPlayer - Audio playback
  • javafx.scene.media.Media - Audio resources

JavaFX Media 21

Audio and video playback support for JavaFX. Used in this project for playing the "Who's That Pokemon?" sound effect.

Why JavaFX Media?

  • Native support for MP3, WAV, and other audio formats
  • Simple API for audio playback control
  • Integrated with JavaFX event system
  • Good performance for UI sound effects

Key Classes Used: javafx.scene.media.MediaPlayer and javafx.scene.media.Media

Jackson Databind 2.15.2

High-performance JSON processor for Java. Handles serialization and deserialization between JSON and POJOs.

Why Jackson?

  • Fast and efficient JSON parsing
  • Automatic mapping to Java objects
  • Support for generic collections (List, Map)
  • Annotation-based customization available
  • Widely used industry standard

Key Class Used: com.fasterxml.jackson.databind.ObjectMapper

Java Module System Configuration

The project uses JPMS (Java Platform Module System). The module-info.java file declares module dependencies and accessibility:

module com.example {
    // JavaFX dependencies
    requires javafx.controls;
    requires javafx.graphics;
    requires javafx.media;        // Required for sound effects!
    requires javafx.fxml;
    
    // Jackson dependencies for JSON parsing
    requires com.fasterxml.jackson.databind;
    requires com.fasterxml.jackson.core;
    requires com.fasterxml.jackson.annotation;
    
    // Export packages (make accessible to other modules)
    exports com.example;
    exports com.example.controller;
    exports com.example.view;
    exports com.example.model;
    
    // Open packages for reflection (needed for Jackson)
    opens com.example.model to com.fasterxml.jackson.databind;
}
Important: The opens directive is critical for Jackson. Without it, Jackson cannot use reflection to access private fields in the Pokemon class, resulting in deserialization errors. Also note that requires javafx.media is essential for sound playback.
Build Configuration

Key Maven plugin configuration for running the JavaFX application:

<plugin>
    <groupId>org.openjfx</groupId>
    <artifactId>javafx-maven-plugin</artifactId>
    <version>0.0.8</version>
    <executions>
        <execution>
            <id>default-cli</id>
            <configuration>
                <mainClass>com.example.App</mainClass>
            </configuration>
        </execution>
    </executions>
</plugin>

This plugin handles JavaFX module path configuration automatically, allowing you to run the application with mvn javafx:run.

Alternative Dependency Management

If not using Maven: You'll need to manually configure module paths and classpath. Here's how for different build systems:

Gradle Configuration:

plugins {
    id 'application'
    id 'org.openjfx.javafxplugin' version '0.0.14'
}

javafx {
    version = "21"
    modules = ['javafx.controls', 'javafx.fxml', 'javafx.media']
}

dependencies {
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.2'
}

application {
    mainModule = 'com.example'
    mainClass = 'com.example.App'
}

Manual Compilation (command line):

# Compile
javac --module-path /path/to/javafx-sdk-21/lib:jackson-jars \
--add-modules javafx.controls,javafx.media,com.fasterxml.jackson.databind \
-d out src/main/java/com/example/*.java

# Run
java --module-path /path/to/javafx-sdk-21/lib:jackson-jars:out \
--add-modules javafx.controls,javafx.media,com.fasterxml.jackson.databind \
com.example.App

Best Practices

Code Organization

  • MVC Separation: Keep business logic in Model, UI in View, coordination in Controller. Never access View directly from Model or vice versa - always go through Controller.
  • Constants: UI coordinates and dimensions are defined as constants at the top of the View class for easy maintenance. Group related constants together.
  • Resource Management: Pass the Class object for resource access to ensure portability between development and production environments. Always use getResourceAsStream() for files in the JAR.
  • Error Handling: Check for null resources and handle loading failures gracefully with try-catch blocks and user feedback. Especially important for audio files.
  • State Validation: Always verify powered-on state before allowing interactions. Use guard clauses at the start of Controller methods.
  • Media Resource Cleanup: Stop previous MediaPlayer instances before starting new ones to prevent audio overlap.
MVC Best Practices
✅ DO ❌ DON'T
Keep Model completely UI-independent - should work without JavaFX Import JavaFX classes in Model layer
Make View a passive component that only displays data Put business logic or state management in View
Have Controller mediate all communication between layers Let Model directly update View or View directly change Model
Pass resource Class from App to View and Controller for consistent resource loading Use getClass() inside View/Controller (may fail in JAR)
Keep methods focused with single responsibility (one method does one thing) Create large multi-purpose methods that do many things
Security & Validation
  • JSON Validation: Validate JSON structure before deserialization to prevent parsing errors
  • Array Bounds: Check array bounds before accessing Pokemon list (especially with user-driven navigation)
  • Resource Existence: Handle missing image files gracefully with fallback images or error messages. Same for audio files.
  • Input Sanitization: If adding search functionality, sanitize user input to prevent injection issues
  • Data Validation: Validate evolution stage values (1-3), dex numbers (1-151), and ensure required fields exist
  • Type Safety: Use strong typing and avoid raw types or excessive casting
Performance Considerations

Current Implementation:

  • Lazy Image Loading: Images are loaded on-demand per Pokemon, not all at startup - saves memory
  • JSON Caching: JSON is loaded once at startup and cached in memory for the application lifetime
  • Effect Reuse: ColorAdjust effect is created once and reused for all silhouettes
  • Font Sharing: Custom font is loaded once and shared across all labels
  • Sound Management: MediaPlayer instance is reused, stopping previous playback before starting new

Optimization Opportunities:

  • Image Caching: Cache loaded images to avoid reloading when navigating back to previously viewed Pokemon
  • Preloading: Preload adjacent Pokemon images in background for smoother navigation
  • Virtual Scrolling: If implementing a grid view, only render visible items
  • Thumbnail Generation: Create smaller thumbnails for list views to reduce memory usage
  • Audio Preloading: Preload sound effect at startup to eliminate first-play delay
Code Quality Guidelines
  • Naming Conventions: Use descriptive names (handlePowerOn not doThing), follow Java naming standards
  • Documentation: Add Javadoc comments to public methods explaining parameters and return values
  • Method Length: Keep methods short (ideally under 30 lines) - extract complex logic into helper methods
  • Magic Numbers: Avoid magic numbers in code - use named constants with descriptive names
  • DRY Principle: Don't Repeat Yourself - extract repeated code into reusable methods
  • Error Messages: Provide helpful error messages that guide users or developers to solutions
  • Logging: Use proper logging (java.util.logging) instead of System.out.println for production code
Testing Recommendations

While the current project doesn't include tests, here's what you should test if expanding:

Model Layer (Easy to Unit Test):

  • Navigation boundary conditions (wrap-around)
  • Power state transitions
  • Reveal/hide toggle behavior
  • Data loading and parsing
  • State consistency after operations

Controller Layer (Integration Tests):

  • Event handler responses
  • View update triggers
  • State validation enforcement

View Layer (Manual/Visual Tests):

  • UI rendering correctness
  • Button positioning accuracy
  • Effect application (silhouettes)
  • Text wrapping and fitting
  • Sound playback functionality
Version Control Best Practices

.gitignore recommendations:

# Build artifacts
target/
*.class
*.jar
*.war

# IDE files
.idea/
.vscode/
*.iml
.project
.classpath
.settings/

# OS files
.DS_Store
Thumbs.db

# Maven
dependency-reduced-pom.xml

# Logs
*.log

Commit Message Guidelines:

  • Use present tense: "Add feature" not "Added feature"
  • Be specific: "Fix navigation wrap-around bug" not "Fix bug"
  • Reference issues/tickets when applicable
  • Keep first line under 50 characters
  • Add detailed explanation in body for complex changes