A full-stack web game where players find hidden characters in detailed scenes and compete for the fastest time on the leaderboard.
This is a modern implementation of the classic "Where's Waldo?" game, built with a full-stack TypeScript architecture. Players search for specific characters in detailed scenario images, with their completion times tracked and compared against other players on a leaderboard system.
The application features:
- Interactive gameplay: Click to locate characters within large scenario images
- Real-time validation: Instant feedback when selecting character locations
- Time tracking: Precise timing from game start to completion
- Leaderboard system: Top 10 scores saved per scenario
- Multiple scenarios: Different scenes with unique characters to find
This is a monorepo containing two main packages:
RESTful API built with Node.js and Express that handles:
- Character coordinate validation
- Scenario and character data management
- Score persistence and leaderboard queries
- PostgreSQL database with Drizzle ORM
React-based single-page application featuring:
- React 19 with TypeScript
- TanStack Query for server state management
- Zustand for client state management
- React Router for navigation
- Tailwind CSS for styling
- Vite for build tooling
- Character Detection: Click on the image to mark where you think characters are hiding
- Target Box: Visual feedback showing your selected area
- Character Menu: Track which characters you've found
- Score Timer: Real-time timer tracking your progress
- Winner Modal: Celebration screen with time and leaderboard qualification
- Top 10 Leaderboard: Submit your score if you make it to the top 10
- Multiple Scenarios: Choose from different scenes with varying difficulty
- Responsive Design: Works on desktop and mobile devices
- React 19 - UI framework
- TypeScript - Type safety
- Vite - Build tool and dev server
- TanStack Query - Server state management
- Zustand - Client state management
- React Router 7 - Routing
- Tailwind CSS 4 - Styling
- Axios - HTTP client
- Vitest - Unit testing
- Playwright - End-to-end testing
- Testing Library - Component testing
- Node.js - Runtime
- Express 5 - Web framework
- TypeScript - Type safety
- Drizzle ORM - Database ORM
- PostgreSQL - Database
- Zod - Schema validation
- Vitest - Testing framework
- Supertest - API testing
- pnpm - Package manager
- Biome - Linting and formatting
- tsx - TypeScript execution
- Drizzle Kit - Database migrations
- Node.js >= 20
- pnpm >= 10
- PostgreSQL database
-
Clone the repository:
git clone https://github.com/danielz0102/where-is-waldo.git cd where-is-waldo -
Install dependencies:
pnpm install
-
Set up environment variables:
Create
.envfile in the/apidirectory. Only these variables are mandatory:DEV_DB_URL=postgresql://user:password@localhost:5432/waldo_dev TEST_DB_URL=postgresql://user:password@localhost:5432/waldo_test
Create
.envfile in the/webdirectory:VITE_API_URL=http://localhost:3000
-
Set up the database:
cd api pnpm db generate pnpm db migrate pnpm db push -
Seed the database (optional):
pnpm seed:test
Run both frontend and backend concurrently:
pnpm devThis starts:
- API server at
http://localhost:3000 - Web app at
http://localhost:5173
API only:
cd api
pnpm devWeb only:
cd web
pnpm devBuild API:
cd api
pnpm build
pnpm startBuild Web:
cd web
pnpm build
pnpm previewwhere-is-waldo/
├── api/ # Backend API
│ ├── src/
│ │ ├── controllers/ # Request handlers
│ │ ├── models/ # Business logic
│ │ ├── repositories/ # Database access
│ │ ├── routers/ # Route definitions
│ │ ├── schemas/ # Zod validation schemas
│ │ ├── middlewares/ # Express middlewares
│ │ ├── db/ # Database configuration
│ │ └── lib/ # Utility functions
│ ├── tests/ # API tests
│ └── drizzle/ # Database migrations
│
├── web/ # Frontend application
│ ├── src/
│ │ ├── components/ # React components
│ │ ├── pages/ # Page components
│ │ ├── services/ # API services
│ │ ├── querys/ # TanStack Query hooks
│ │ ├── stores/ # Zustand stores
│ │ ├── useCases/ # Business logic
│ │ └── lib/ # Utility functions
│ ├── tests/ # Frontend tests
│ │ ├── e2e/ # Playwright tests
│ │ └── integration/ # Component tests
│ └── public/ # Static assets
│
├── biome.json # Biome configuration
├── pnpm-workspace.yaml # pnpm workspace config
└── vitest.config.ts # Vitest configuration
# API tests
cd api
pnpm test
# Web unit tests
cd web
pnpm test
# Web E2E tests
cd web
pnpm test:e2e# API
cd api
pnpm check
# Web
cd web
pnpm check# Lint
pnpm lint
# Fix linting issues
pnpm lint:fix
# Format code
pnpm formatGET /api/scenarios- Get all scenariosGET /api/scenarios/:id- Get scenario by IDGET /api/scenarios/slug/:slug- Get scenario by slug
GET /api/characters/scenario/:scenarioId- Get characters for a scenarioPOST /api/characters/validate- Validate character location
GET /api/scores/scenario/:scenarioId- Get top 10 scores for a scenarioPOST /api/scores- Submit a new scoreGET /api/scores/isTop10/:scenarioId/:seconds- Check if time qualifies for top 10
id- UUID primary keyname- Scenario nameslug- URL-friendly identifierimgUrl- Image URL
id- UUID primary keyname- Character nameimgUrl- Character image URLminX,maxX,minY,maxY- Coordinate boundariesscenarioId- Foreign key to scenarios
id- UUID primary keyusername- Player usernametime- Completion timescenarioId- Foreign key to scenarios
- Select a Scenario: Choose a scene from the scenario selection screen
- Find the Characters: Character portraits appear at the top of the screen
- Click to Search: Click anywhere on the image where you think a character is hiding
- Select Character: A menu appears - click the character you found
- Win the Game: Find all characters as quickly as possible
- Submit Score: If you're fast enough, submit your name to the leaderboard
- Add scenario image to your hosting service
- Insert scenario record in database with image URL
- Add character records with coordinate boundaries
- Characters will automatically appear in the game
cd api
pnpm db generate # Generate migration from schema changes
pnpm db migrate # Run migrations
pnpm db push # Push schema to database
pnpm db studio # Open Drizzle Studio- Images are loaded from external CDN
- Query results cached with TanStack Query
- Optimistic updates for better UX
- Lazy loading for route components
- Production builds minified and optimized
Inspired by the classic "Where's Waldo?" books by Martin Handford.
