A modern, animated portfolio site built with Next.js, Tailwind CSS, and Sanity CMS. Features GitHub, LeetCode, Last.fm, and Steam integrations on a dedicated Signals page.
- Framework: Next.js 16 (Pages Router)
- Styling: Tailwind CSS 3
- Animations: Framer Motion 11
- Content Management: Sanity CMS
- Language: TypeScript 5
- Deployment: Vercel
├── components/
│ ├── site/ # Layout and site components
│ ├── Navbar/ # Navigation bar
│ ├── SplashScreen/ # Entry animation
│ └── HomeSections/ # Home page section variants
├── pages/
│ ├── index.tsx # Home/overview page
│ ├── signals.tsx # GitHub, LeetCode, Last.fm, Steam stats
│ ├── splash.tsx # Splash screen page
│ └── api/
├── lib/ # Data fetchers and utilities
│ ├── github.ts # GitHub API integration
│ ├── leetcode.ts # LeetCode GraphQL integration
│ ├── lastfm.ts # Last.fm API integration
│ ├── steam.ts # Steam Web API integration
│ └── ...
├── sanity/
│ ├── env.ts # Centralized environment configuration
│ ├── lib/
│ │ ├── types.ts # All TypeScript interfaces
│ │ ├── fetch.ts # Sanity CMS fetch utility
│ │ └── queries.ts # GROQ queries
│ └── studio/ # Sanity Studio config
├── styles/
│ └── globals.css # Global styles and animations
├── public/ # Static assets
├── .env.example # Environment template
└── tsconfig.json # TypeScript configuration
git clone <repository-url>
cd portfolio
npm installCopy the environment template and fill in your values:
cp .env.example .env.localEdit .env.local with your API keys and IDs (see Environment Variables section below).
npm run devOpen http://localhost:3000 to view the site.
To edit content in the CMS:
npm run sanity:studioSanity Studio will open at http://localhost:3333.
All environment variables are centralized in sanity/env.ts for type safety and consistency.
NEXT_PUBLIC_SANITY_PROJECT_ID=your_sanity_project_id
NEXT_PUBLIC_SANITY_DATASET=your_sanity_dataset
SANITY_API_TOKEN=your_sanity_api_token_with_write_accessGet these from your Sanity project dashboard.
GITHUB_TOKEN=your_github_personal_access_tokenIf not provided, the page uses public GitHub REST API with rate limiting (~60 requests/hour).
LEETCODE_USERNAME=your_leetcode_usernamePublic GraphQL endpoint—no API key needed. Username extracted from Sanity resource links or env var.
LASTFM_API_KEY=your_lastfm_api_key
LASTFM_USERNAME=your_last_fm_username (optional)Get an API key from Last.fm. If not provided in env, username is extracted from Sanity resource links.
STEAM_API_KEY=your_steam_web_api_key
STEAM_ID=your_steam_profile_id_or_steamid64 (optional)Get an API key from Steam Community. STEAM_ID can be:
- A 17-digit SteamID64
- Your vanity URL segment (e.g.,
your-vanity-namefromsteamcommunity.com/id/your-vanity-name)
If not provided in env, ID is extracted from Sanity resource links.
Main portfolio landing page. Displays featured projects, research papers, and resource links managed in Sanity CMS.
Key files:
pages/index.tsx– Page componentcomponents/HomeSections/– Section variantssanity/lib/queries.ts– GROQ queries for home content
To update: Edit content in Sanity Studio, or modify queries in sanity/lib/queries.ts.
Dashboard aggregating GitHub, LeetCode, Last.fm, and Steam stats.
Features:
- GitHub: Recent repositories, contribution heatmap, follower stats
- LeetCode: Problem-solving stats, difficulty breakdown, global rank
- Last.fm: Top monthly artists and tracks, total scrobbles
- Steam: Library size, total play hours, top games, recent games
Key files:
pages/signals.tsx– Page componentlib/github.ts,lib/leetcode.ts,lib/lastfm.ts,lib/steam.ts– Fetcherssanity/lib/types.ts– Type definitions
To update: Each stat fetcher is independent. Modify the corresponding lib/<service>.ts to change what data is fetched or displayed.
Animated entry screen displayed when the site first loads.
Key files:
pages/splash.tsx– Page componentcomponents/SplashScreen/– Splash componentsstyles/globals.css– Animations
- Run
npm run sanity:studio - Browse to Studio and edit:
- Featured projects
- Research papers
- Resource links (profile URLs for social/external links)
- Site settings
- Home page content:
sanity/lib/queries.ts(GROQ queries) - Signals integrations: Update environment variables in
.env.localor modify fetchers inlib/ - Styling:
styles/globals.css(Tailwind, custom animations) - Layout:
components/site/SiteLayout.tsx - Animations:
components/site/motion.ts(Framer Motion configs)
npm run buildRuns TypeScript type checking and Next.js build. Output in .next/.
npx tsc --noEmitVercel is pre-configured and deploys on every push to main:
- Connect your GitHub repo to Vercel
- Set environment variables in Vercel project settings
- Push to
mainto deploy
Deployment docs: Vercel Next.js deployment
Modify orbit speeds in styles/globals.css:
.solar-system– Container animation duration.orbit-*– Individual orbit timingscomponents/site/SiteLayout.tsx– Motion parameters
Edit tailwind.config.js or override in styles/globals.css.
- Update
.env.localwith new keys - Modify fetchers in
lib/ - Update types in
sanity/lib/types.ts - Rewire component in
pages/signals.tsx
npm run dev # Start dev server
npm run build # Build for production
npm run start # Start production server
npm run type-check # Run TypeScript checks
npm run sanity:studio # Launch Sanity StudioRun npx tsc --noEmit locally to debug before pushing.
- Check
.env.localhas required keys - Check
sanity/env.tsfor env var names - Check browser console for fetch errors
- Verify API keys are valid and not rate-limited
- Ensure
SANITY_API_TOKENhas write permissions - Rebuild or redeploy after content changes in Studio
MIT