A campus exploration and location-guessing game built specifically for students, alumni, and visitors of NIT Jalandhar.
- Overview
- Key Features
- Design System and Aesthetics
- Technical Architecture
- Tech Stack
- Folder Structure
- Local Development Setup
- Gameplay and Scoring Engine
- Development and Contribution Guidelines
- Roadmap
GeoGuessr: NITJ Edition is an interactive web-based campus exploration game. Players are shown photographic spots or 360° panoramas of various campus locations at NIT Jalandhar and must pinpoint the locations on an interactive custom campus map.
The game is designed to:
- Help new students (freshers) familiarize themselves with the campus layout.
- Create a nostalgic experience for alumni and a fun game for the current student community.
- Support healthy competition through daily challenges and club-hosted leaderboards.
- Spot Mode: Guess the location based on a single high-quality photograph (e.g., library entrance, hostel corridor, sports ground, or hidden paths).
- Panorama Mode (Future): View and interact with a 360° panoramic view of the location (rotate and zoom enabled) to guess the campus coordinates.
- Leaderboards: Track top scores globally, with daily and all-time records. Includes username, score, and customizable student tag/hostel affiliation.
- User Accounts & Profiles: Authenticate securely using Google OAuth (restricted to NITJ emails) to track games played, high scores, total scores, and accuracy.
- Admin Portal: A dedicated administrative dashboard to:
- Upload new location images.
- Pick coordinates interactively from a map.
- Set difficulty levels (
easy,medium,hard) and tags (hostel,academic,canteen,sports, etc.). - Delete existing locations.
Following the NITJ Guessr brand identity, the game UI is designed to feel playful, minimal, calm, and friendly—resembling a game title screen rather than a generic dashboard:
- Background: Warm cream paper texture (
#F7F2E8/#F5EFE4). - Watermark: A faint, low-contrast campus blueprint of NIT Jalandhar engraved across the viewport.
- Primary Color: Primary red (
#D94A43) used for active buttons, user profile selectors, and main actions. - Typography: Hand-drawn marker fonts (like Caveat, Kalam, or Permanent Marker) for headings and hand-written annotations, paired with clean sans-serif body fonts (Geist, Inter, Nunito).
- Animations & Sound: Large buttons with slight scale-on-hover and push-on-press micro-animations, paired with satisfying soft pop or woodwind audio feedback.
NITJ Guessr operates on a decoupled client-server architecture inside a single monorepo:
┌──────────────────┐
│ Next.js App │ (Client App)
│ Frontend │
└────────┬─────────┘
│
│ REST API
│
┌────────▼─────────┐
│ API Backend │ (Express API)
│ (TypeScript) │
└────────┬─────────┘
│
┌───────────────┼───────────────┐
│ │ │
┌───────▼───────┐ ┌─────▼─────┐ ┌──────▼──────┐
│ PostgreSQL │ │ Local │ │ Cloudflare │
│ Database │ │ Uploads │ │ R2 Storage │
│ │ │ Folder │ │ (Production)│
└───────────────┘ └───────────┘ └─────────────┘
- Source of Truth: The Backend is the absolute source of truth. The frontend never calculates scores, stores game states permanently, or validates guesses.
- Database Engine: Relies on PostgreSQL. On boot, the backend automatically initializes the database
guessrand creates the necessary tables (users,locations,games,leaderboard). - Storage Engine: Uploaded locations are saved to Cloudflare R2 bucket. In local development where R2 credentials might not be configured, it automatically falls back to local file storage, serving uploaded files through the Express
/uploadsendpoint.
- Framework: Next.js 16 (React 19, TypeScript)
- Styling: Tailwind CSS v4 (built with
@tailwindcss/postcss) - State Management: Zustand (for client game-flow and user sessions)
- Server State: TanStack React Query (for API caching and queries)
- Interactive Map: MapLibre GL
- Effects: Canvas Confetti, Lucide React
- 360° Viewer: Photo Sphere Viewer / Pannellum (dynamic script injection)
- Runtime: Node.js / Bun
- Framework: Express (TypeScript)
- Database Driver:
pg(PostgreSQL Client Pool) - Development Server:
ts-node-dev(hot reloading) - Authentication: Google Auth Library & JsonWebToken (JWT)
guessr/
├── assets/ # Documentation images (screenshots)
├── docs/ # Architecture & Planning references (ignored on build)
├── backend/ # Backend API codebase
│ ├── src/
│ │ ├── config.ts # Environment configurations
│ │ ├── db/ # Postgres setup & migrations (index.ts)
│ │ ├── lib/ # S3/R2 client helper (r2.ts)
│ │ ├── middleware/ # Auth session handlers
│ │ ├── routes/ # API routers (admin, auth, game, leaderboard)
│ │ ├── types/ # TS Interfaces
│ │ └── index.ts # Server entry point
│ ├── .env.example # Template for backend variables
│ ├── package.json # Backend dependencies & scripts
│ └── tsconfig.json
└── frontend/ # Next.js frontend codebase
├── public/ # Static assets (fonts, audio, etc.)
├── src/
│ ├── app/ # App Router pages (landing, game, admin, globals.css)
│ └── lib/ # Global audio configurations & Zustand store
├── package.json # Frontend dependencies & scripts
└── tsconfig.json
Follow these steps to run both the frontend and backend locally.
- Node.js (v18+) or Bun
- PostgreSQL instance running locally or hosted (e.g. Neon, Supabase)
Ensure you have a PostgreSQL server running on port 5432.
- You can manually create a database named
guessr, or let the backend attempt to create it automatically on startup (provided the user specified in the connection string has permission to create databases).
- Navigate to the backend directory:
cd backend - Install the backend dependencies:
npm install
- Create your
.envfile from the template:cp .env.example .env
- Open backend
.envand fill in the values:- DATABASE_URL: Update with your Postgres username, password, host, and port (e.g.
postgresql://postgres:password@localhost:5432/guessr). - GOOGLE_CLIENT_ID & GOOGLE_CLIENT_SECRET: Add your Google OAuth credentials to support sign-in.
- ADMIN_EMAILS: Add your email address to grant yourself admin access for uploading locations.
- R2 Credentials (Optional): If left blank, uploads default to the local
backend/uploads/directory.
- DATABASE_URL: Update with your Postgres username, password, host, and port (e.g.
- Start the development server:
The backend API will start running on
npm run dev
http://localhost:5000.
- Navigate to the frontend directory:
cd ../frontend - Install the frontend dependencies:
npm install
- Start the Next.js development server:
The client application will start running on
npm run dev
http://localhost:3000. Open this address in your browser.
Note: The frontend is currently configured to connect to the backend at http://localhost:5000/api.
A game session consists of 5 rounds. In each round, the player is presented with a random location image. The player places a guess on the campus map and clicks Submit Guess.
Scores are calculated based on the Haversine distance between the actual coordinates and the player's guess:
- 0 - 10 meters:
5000points (Perfect guess) - 10 - 25 meters:
4500points - 25 - 50 meters:
4000points - 50 - 100 meters:
3000points - 100 - 250 meters:
2000points - 250+ meters: Exponentially decays down to
0 - 1000points based on distance.
All contributors must follow these guidelines:
- TypeScript Everywhere: Avoid
anyor loose types. Prefer explicit type declarations. - Component Responsibilities: Do not place heavy business logic directly inside components. Use Zustand stores for client-side state and backend services for API state.
- Keep Functions Small: Focus on readability, unit testing, and composition.
- Use Next.js Server Components by default for static UI layouts, and Client Components (
"use client") only for interactive game elements and MapLibre canvas integration. - Use TanStack Query for caching and API synchronization.
- Follow the color schemes, cream background textures, and marker fonts specified in the Design System.
- Follow a service-repository pattern:
- Routes should only handle request parsing, authentication check, and response formatting.
- Move all business logic into service modules.
- Put database query operations in db client files.
Follow these prefix rules when creating branches:
- Feature Branches:
feature/location-upload,feature/panorama-mode - Fixes:
fix/scoring-decay,fix/mobile-responsive
- Phase 1: Spot Mode core gameplay, MapLibre map guessing, scoring engine, user stats, and local setup.
- Phase 2: Admin panel with interactive map pin-drop coordinate tagging and photo uploads.
- Phase 3: Panorama Mode integration with 360° interactive view using Photo Sphere Viewer / Pannellum.
- Phase 4: Expanded leaderboards (weekly and daily filtration) and Google OAuth integrations.
- Phase 5: Daily Challenge (all users get the same 5 locations daily to compete for top spots).
- Phase 6: Community-driven location submissions and club challenges.



