A simple TypeScript React app for practicing katakana reading using Pokemon from the PokeAPI.
- Random Pokemon from all generations (default forms only, excludes mega evolutions and variations)
- Instant Pokemon switching - All data loaded upfront for zero-delay transitions
- Display Pokemon sprite with katakana name
- Input validation supporting multiple romaji romanization variants
- Instant feedback on correct/incorrect answers with answer reveal
- Automatic progression to next Pokemon on correct answer
- Long vowel marker (ー) support for accurate katakana romanization
- Vite - Fast build tool
- React 18 - UI framework
- TypeScript - Type safety
- Tailwind CSS - Styling
- WanaKana - Katakana-to-romaji validation
- PokeAPI GraphQL - Pokemon data source
npm installnpm run devVisit http://localhost:5173/ to use the app.
npm run build- A random Pokemon appears with its name in katakana
- Type the romaji romanization in the input field
- Press Enter or click Submit
- If correct, you'll see a success message and move to the next Pokemon
- If incorrect, try again with a different romanization
The app accepts multiple romanization variants thanks to WanaKana:
- Long vowels:
ō,ou,oo, oro - Examples for Pikachu (ピカチュウ):
pikachu✓pikachuu✓pikatyuu✓
src/
├── components/
│ ├── PokemonCard.tsx # Pokemon display
│ ├── RomajiInput.tsx # Input field
│ └── FeedbackMessage.tsx # Success/error messages
├── hooks/
│ └── usePokemon.ts # Pokemon data fetching
├── utils/
│ └── katakana.ts # Romaji validation
├── types/
│ └── pokemon.ts # TypeScript interfaces
├── App.tsx # Main component
├── main.tsx # Entry point
└── index.css # Tailwind directives
- No code duplication - Single source of truth for state, logic separated into hooks and utils
- Presentational components - All UI components are stateless and receive data via props
- Type safety - Full TypeScript coverage
- Clean architecture - Separation of concerns between data fetching, validation, and presentation
- Performance optimized - All default Pokemon fetched with single GraphQL query on initial load, then cached for instant transitions
The app uses GraphQL to efficiently fetch all Pokemon data on initial load:
- Initial load: ~3-5 seconds with single GraphQL query for all default Pokemon (1000+ Pokemon)
- Pokemon transitions: Instant (0ms) - selects from cached data
- Network requests: 1 GraphQL query (fetches only required fields: id, name, sprites, Japanese names)
- Memory footprint: ~1MB for cached Pokemon data
- Query optimization: Filters to
is_default: trueto exclude mega evolutions and form variations - Previous REST approach: 302 requests for 151 Pokemon - migrated to GraphQL for better performance