A modern movie discovery and recommendation platform built with Next.js, featuring personalized recommendations, watchlist management, completed-movie tracking, a Chrome extension for automatic detection, and a cinematic retro-terminal UI.
Live at recon-six-bay.vercel.app
- π¬ Browse popular and trending movies from TMDB
- π Search for movies with real-time results
- π Personal watchlist management
- β Mark movies as watched (completed) with separate tracking
- π― Personalized recommendations powered by quiz preferences and watch history
- π Adaptive recommendation engine β quiz influence decays as you watch more movies
- π Viewing Insights on your profile (top genres, influence breakdown)
- β³ Recalibrate preferences inline from your profile β no need to redo the full quiz
- π§© Chrome Extension β automatically detects movies on Netflix, Prime Video, and any streaming site
- π Token-based extension auth for secure cross-origin syncing
- π Authentication via Google OAuth or email/password
- π Dark retro-terminal theme with cinematic UI
- π€ Procedural 3D robot mascot on the landing page (Three.js)
- β¨ Ambient floating particle background (instanced mesh)
- πΊ CRT page transition effect on route changes
- π 3D tilt-on-hover movie cards with cursor-following glow
- π‘ Interactive "Signal Lost" 404 page with glitch text & CRT static
- π 3D genre radar chart on profile (mouse-tilt interactive)
- ποΈ CRT poster frame on movie details & VHS tape header on watchlist
- π΅ Cassette tape loading spinner with animated reels
- π± Fully responsive design
| Route | Description |
|---|---|
/ |
Landing page |
/home |
Personalised homepage with recommendations |
/search |
Movie search |
/movie/[id] |
Movie details + per-movie recommendations |
/watchlist |
Movies saved to watch later |
/completed |
Movies you've watched |
/profile |
User info, viewing insights, preference recalibration, and extension setup |
/onboarding/preferences |
Quiz-based preference setup |
/login |
Sign in |
/signup |
Create account |
Recommendations blend three signals with adaptive weighting:
- Quiz preferences β genres, moods, era, pacing, popularity selected during onboarding
- Watchlist activity β genres and recency of saved movies
- Completed movies β strongest signal; movies the user actually watched
As the user completes more movies, quiz influence decays in favour of watch history:
quizWeight = max(0.30, 1 β completedCount / (completedCount + 10))
completedWeight = 1 β quizWeight
| Completed Movies | Quiz Weight | Watch History Weight |
|---|---|---|
| 0 | 100% | 0% |
| 5 | 67% | 33% |
| 10 | 50% | 50% |
| 20 | 33% | 67% |
| 50+ | 30% (floor) | 70% |
This is applied consistently across both /api/movies/recommend/[id] (per-movie) and /api/recommendations (homepage).
The Recon Chrome Extension (GitHub repo) automatically detects movies playing on streaming sites and syncs them to your Recon watchlist.
- Content script runs on every page and watches for
<video>elements - Platform-specific detection for Netflix (URL-based) and Prime Video (MutationObserver)
- Generic mode works on any site with a video player (pstream, 123movies, etc.)
- Extracts the movie title from DOM elements,
aria-label, ordocument.title - Smart title cleaning strips quality tags, site names, and streaming noise
- Year extraction from meta tags and page text for accurate TMDB matching
- Badge indicator on the extension icon when a movie is detected
- Popup lets you Add to Watchlist, Mark Completed, or Ignore
- Clone the extension repo
- Open
chrome://extensionsβ enable Developer mode - Click Load unpacked β select the cloned folder
- Go to your Profile page on recon-six-bay.vercel.app
- Click Generate Token under the Chrome Extension section
- Copy the token
- Click the Recon extension icon β β gear β paste token β Save
The extension authenticates via Authorization: Bearer <token> headers. Tokens are SHA-256 hashed in the database.
- Frontend: Next.js 16, React 19, TypeScript, Tailwind CSS v4
- 3D / Animation: Three.js, React Three Fiber, drei, Framer Motion
- Authentication: NextAuth.js v5 (beta) with Google OAuth & Credentials
- Database: Supabase (PostgreSQL)
- API: TMDB for movie data
- Deployment: Vercel
The app uses a custom retro-terminal design system (#0b0b0b background, #c8a832 amber primary, #4abfad teal accent, Geist Mono font).
| Feature | Location | Description |
|---|---|---|
| Procedural 3D Robot | Landing hero | BMO-inspired mascot with glitch animations, spark particles, and CRT screen β built procedurally in Three.js |
| Ambient Particles | Site-wide | 80 instanced teal/amber dots floating upward with sine-wave motion |
| CRT Page Transition | Site-wide | Screen darkens β squishes to a glowing horizontal line β fades out on route changes |
| 3D Tilt Cards | All movie cards | Cards rotate Β±6Β° toward cursor with perspective transform and radial teal glow |
| Signal Lost 404 | /not-found |
Canvas noise, scrambling glitch text, red pulsing LED, terminal error log |
| Genre Radar | Profile | Three.js spider chart with amber data polygon, teal wireframe grid, mouse-tilt interaction |
| CRT Poster Frame | Movie detail | Corner brackets, teal glow, NOW PLAYING label, scanline overlay on poster |
| VHS Tape Header | Watchlist | Side colour stripes, decorative reel counter, gradient accent line |
| Cassette Loader | Loading states | Spinning reels with spokes, tape body, "RECON MIX" label above progress bar |
| Typewriter Reveal | Landing hero | Character-by-character heading animation with blinking cursor |
MovieRec/
βββ Recon_v0/ # Next.js frontend
β βββ app/
β β βββ api/
β β β βββ movies/ # TMDB proxy routes (search, trending, popular, recommend)
β β β βββ recommendations/ # Homepage personalised recommendations
β β β βββ watchlist/ # Watchlist CRUD + status management
β β β βββ preferences/ # User quiz preferences
β β β βββ extension/ # Chrome extension endpoints
β β β β βββ token/ # Generate / revoke API tokens
β β β β βββ watchlist/ # Extension watchlist sync (token auth)
β β β βββ signup/ # Account creation
β β βββ home/ # Authenticated homepage
β β βββ movie/[id]/ # Movie detail page
β β βββ search/ # Search page
β β βββ watchlist/ # Watchlist page (status = "watchlist")
β β βββ completed/ # Completed movies page (status = "completed")
β β βββ profile/ # Profile, Viewing Insights, Recalibrate, Extension setup
β β βββ onboarding/ # Preference quiz
β β βββ login/ # Login page
β β βββ signup/ # Signup page
β βββ components/
β β βββ retro/ # Retro UI components (3D models, particles, transitions)
β β βββ layouts/ # Auth & main layout wrappers
β β βββ ui/ # shadcn/ui primitives (Button, Card, etc.)
β βββ lib/ # Utilities (watchlist, genres, TMDB, Supabase)
β βββ hooks/ # Custom hooks (useToast)
βββ recon-extension/ # Chrome Extension (MV3)
β βββ manifest.json # Extension manifest
β βββ background.js # Service worker (sync + badge)
β βββ content.js # Content script (video detection)
β βββ popup.html/css/js # Extension popup UI
β βββ icon-128.png # Extension icon
βββ backend/ # Flask backend (optional, legacy)
βββ app.py
The app uses five Supabase tables:
| Table | Key Columns |
|---|---|
users |
id, email, name, image |
user_credentials |
user_id, password_hash |
user_preferences |
user_id, genres, moods, era, pacing, popularity, completed |
watchlist |
user_id, movie_id, movie_title, poster_path, status, created_at |
extension_tokens |
user_id, token_hash, created_at |
The watchlist.status column supports "watchlist" (default) and "completed".
If upgrading from a version without the status column:
ALTER TABLE watchlist ADD COLUMN IF NOT EXISTS status text NOT NULL DEFAULT 'watchlist';To add Chrome extension token support:
CREATE TABLE IF NOT EXISTS public.extension_tokens (
user_id uuid PRIMARY KEY REFERENCES public.users(id) ON DELETE CASCADE,
token_hash text NOT NULL,
created_at timestamptz NOT NULL DEFAULT now()
);
ALTER TABLE public.extension_tokens ENABLE ROW LEVEL SECURITY;| Method | Route | Description |
|---|---|---|
| GET | /api/movies/popular |
Popular movies |
| GET | /api/movies/trending |
Trending movies |
| GET | /api/movies/search?q= |
Search movies |
| GET | /api/movies/[id] |
Movie details |
| GET | /api/movies/recommend/[id] |
Per-movie recommendations (adaptive scoring) |
| GET | /api/recommendations |
Homepage personalised recommendations |
| GET | /api/watchlist |
User watchlist (supports ?status= filter) |
| POST | /api/watchlist |
Add to watchlist |
| PATCH | /api/watchlist |
Update status (watchlist β completed) |
| DELETE | /api/watchlist |
Remove from watchlist |
| GET | /api/preferences |
User quiz preferences |
| POST | /api/preferences |
Save / recalibrate quiz preferences |
| POST | /api/signup |
Create account |
| GET | /api/extension/token |
Check if extension token exists |
| POST | /api/extension/token |
Generate new extension API token |
| DELETE | /api/extension/token |
Revoke extension token |
| POST | /api/extension/watchlist |
Add movie from Chrome extension (token auth) |
- Clone the repository
- Navigate to the frontend directory:
cd Recon_v0 - Create
.env.localusing.env.example - Set required environment variables (see below)
- Install dependencies and run:
The app will be available at
npm install npm run dev
http://localhost:3000
If you want to run the legacy Flask backend instead of Next.js TMDB routes:
-
Navigate to the backend directory:
cd backend -
Create
.envusing.env.example -
Set up Python environment:
python -m venv .venv # Windows .venv\Scripts\activate # macOS/Linux source .venv/bin/activate
-
Install dependencies and run:
pip install -r requirements.txt python app.py
The API will be available at
http://localhost:5000 -
Set
BACKEND_URL=http://localhost:5000inRecon_v0/.env.local
| Variable | Description |
|---|---|
TMDB_API_KEY |
TMDB API key (required for movie data) |
GOOGLE_CLIENT_ID |
Google OAuth client ID |
GOOGLE_CLIENT_SECRET |
Google OAuth client secret |
NEXTAUTH_SECRET |
NextAuth.js secret key |
NEXTAUTH_URL |
App URL. Use http://localhost:3000 locally and https://recon-six-bay.vercel.app in production. |
AUTH_URL |
Optional explicit Auth.js base URL. If set, keep it identical to NEXTAUTH_URL. |
NEXT_PUBLIC_SUPABASE_URL |
Supabase project URL |
NEXT_PUBLIC_SUPABASE_ANON_KEY |
Supabase anonymous key |
SUPABASE_SERVICE_ROLE_KEY |
Supabase service role key (server-only) |
BACKEND_URL |
Optional: Flask backend URL |
For the current Vercel deployment, set both NEXTAUTH_URL and AUTH_URL to https://recon-six-bay.vercel.app in your Vercel environment variables. Keep http://localhost:3000 in .env.local when developing locally.
If PowerShell blocks npm due to execution policy, run via cmd:
cmd /c npm run devMIT