Jyotil Agrawal Dhaval Reddy Pucha Ricky Correia
A complete location-based campus discovery game for the University of Georgia. Players explore campus by solving daily location challenges to discover landmarks.
uga-campus-explorer/
โโโ frontend/ # React frontend application
โ โโโ src/
โ โ โโโ components/ # React components
โ โ โโโ pages/ # Page components
โ โ โโโ hooks/ # Custom hooks
โ โ โโโ lib/ # Utility functions
โ โ โโโ types/ # TypeScript types
โ โโโ public/ # Static assets
โ โโโ package.json # Frontend dependencies
โโโ backend/ # Node.js Express API
โ โโโ src/
โ โ โโโ controllers/ # Route controllers
โ โ โโโ routes/ # API routes
โ โ โโโ middleware/ # Express middleware
โ โ โโโ utils/ # Utility functions
โ โ โโโ jobs/ # Scheduled tasks
โ โ โโโ scripts/ # Database scripts
โ โโโ supabase-schema.sql # Database schema
โ โโโ package.json # Backend dependencies
โโโ package.json # Root package.json for monorepo
โโโ README.md # This file
UGA Campus Explorer is a gamified tool built for the UGA community. While thousands of students walk through the Arch every day, many remain "strangers" to the rich history and essential resources of our campus.
Our app provides a Daily 360ยฐ Challenge where students must identify their location on campus. By turning geography into a shared daily ritual, we build a community of Bulldawgs who experienced campus, more connected, and better neighbors.
One of our main challenges was getting the 360ยฐ image rendering to work properly. Initially, we tried to get the entire 3D model using a LiDAR scan to create a VR 3D render, which took way too long to render and had a lot of white space that looked bad. We realized it would be better to take an image like Google Maps Street View, which led us to the 360ยฐ image solution that saved us time and was easier to integrate.
MapLibre was one of the tools we considered for a popup map where users could mark locations. However, the main challenge was that the image was just all green because the map was rendering only the countries and their respective color codes. When we zoomed in, it only showcased green. We shifted to the MapTiler API which has a locked zoom function showing only Athens with buildings and streets, making it easier to provide latitude and longitude for distance calculations.
When we started, we used agentic AI models to write code quickly, but once we began testing we ran into many problems, including integration issues between the frontend and backend. The biggest issue was that AI would make small changes that went unnoticed but caused big problems we didn't want. For example, our authentication integration was failing because the frontend and backend weren't connected at all. We learned a valuable lesson about the importance of carefully checking AI-generated code details.
We built this using React.js and Vite.js for the frontend. The project involved multiple components: one team focused on rendering 360ยฐ images using Polycam and Three.js for the challenge homepage, another worked on the popup map using MapLibre Native and MapTiler for interactive mapping and pin dropping. We connected everything to Supabase for our database and built the backend using Node.js. Key features include the daily challenge, stats page, leaderboard, and how-to guide. We also implemented Gemini AI for generating unique magical stories based on locations.
- Node.js 16.0.0 or higher
- npm 8.0.0 or higher
- Supabase account and project
-
Clone the repository
git clone <repository-url> cd uga-campus-explorer
-
Install dependencies for both frontend and backend
npm run setup
-
Set up environment variables
Backend (.env file in
/backenddirectory):cd backend cp .env.example .envFill in your Supabase credentials and JWT secrets.
Frontend (.env.local file in
/frontenddirectory):cd frontend touch .env.localAdd your frontend environment variables if needed.
-
Set up the database
- Run the SQL schema in your Supabase project
- Seed the database with initial data:
npm run seed
-
Start development servers
npm run dev
This starts both frontend (port 5173) and backend (port 3001) simultaneously.
npm run dev- Start both frontend and backend in development modenpm run build- Build both frontend and backend for productionnpm run test- Run tests for both projectsnpm run lint- Lint both projectsnpm run seed- Seed the backend databasenpm run setup- Install dependencies for both projectsnpm run clean- Remove all node_modulesnpm run reset- Clean and reinstall all dependencies
Frontend (run from /frontend):
npm run dev- Start development servernpm run build- Build for productionnpm run preview- Preview production buildnpm run test- Run testsnpm run lint- Run linting
Backend (run from /backend):
npm run dev- Start development server with nodemonnpm start- Start production servernpm run seed- Seed database with initial datanpm run build- Prepare for production (currently echo command)
- Daily Challenge - New location each day
- Stat - Shows your streaks, best streak, points, locations
- Leaderboards - Compete with other players based on streaks
- How to - How to use the app guide
- Authentication - Secure user registration and login with JWT
- RESTful API - Comprehensive endpoints for all game functionality
- Real-time Statistics - Live leaderboards and user progress tracking
- Scheduled Tasks - Automated new locations for each day
- Security - Rate limiting, input validation, and secure practices
- React 18 - Modern React with hooks
- TypeScript - Type safety and better developer experience
- Vite - Fast development and build tool
- Tailwind CSS - Utility-first CSS framework
- Shadcn/ui - High-quality UI components
- React Router - Client-side routing
- React Query - Server state management
- Supabase Client - Database and authentication
- Node.js - JavaScript runtime
- Express.js - Web application framework
- Supabase - PostgreSQL database with real-time features
- JWT - Authentication tokens
- bcryptjs - Password hashing
- node-cron - Scheduled task execution
- Express Validator - Input validation
- Helmet - Security middleware
- PostgreSQL (via Supabase) - Primary database
- Row Level Security (RLS) - Database-level access control
- Real-time subscriptions - Live data updates
- Automated backups - Data protection
- JWT-based authentication with refresh tokens
- Password hashing with bcrypt
- Rate limiting to prevent abuse
- Input validation and sanitization
- CORS configuration
- Security headers with Helmet
- Row Level Security in database
- Environment variable protection
The backend provides a comprehensive REST API. Key endpoints include:
POST /api/auth/register- User registrationPOST /api/auth/login- User loginGET /api/challenges/today- Get today's challengePOST /api/challenges/submit- Submit challenge answerGET /api/leaderboard- Get leaderboardGET /api/locations- Get all locations
This project is licensed under the MIT License - see the LICENSE file for details.
- Supabase - Backend-as-a-Service for database and authentication
- React.js - Frontend JavaScript library
- Node.js - JavaScript runtime for backend
- Express.js - Web application framework
- MapTiler API - Interactive mapping and geocoding services
- Three.js - 3D graphics library for 360ยฐ image rendering
- MapLibre - Open-source mapping library
- Polycam - 360ยฐ image capture and processing
- Gemini AI - AI-powered story generation
- Vite.js - Build tool and development server
- Tailwind CSS - Utility-first CSS framework
- Shadcn/ui - High-quality UI components
- JWT - Authentication tokens
- bcryptjs - Password hashing
- University of Georgia for inspiration
- StateFarm for being a good neighbor
- All contributors and testers
Built with โค๏ธ for the UGA community ๐