A Next.js application that generates personalized tarot cards from Twitter avatars using Google Gemini AI. Users enter their Twitter handle, and the system creates a mystical tarot card featuring their portrait.
- 🎨 AI-Powered Image Generation - Uses Google Gemini to create tarot cards from Twitter avatars
- 🐦 Twitter Integration - Fetches avatars via Unavatar.io (no Twitter API needed)
- 💾 Handle Tracking - Stores Twitter handles in Supabase database
- 📱 Responsive Design - Beautiful UI built with Tailwind CSS
- 🔗 Social Sharing - Share tarot cards on Twitter
- Framework: Next.js 14 (App Router)
- Language: TypeScript
- Styling: Tailwind CSS
- AI: Google Gemini 2.5 Flash Image Preview
- Database: Supabase (PostgreSQL)
- Avatar Service: Unavatar.io
- Node.js 18+ and npm/yarn
- Google Gemini API key (Get one here)
- Supabase account (Sign up here)
-
Clone or navigate to the project:
cd Parasol-Tarot -
Install dependencies:
npm install
-
Set up environment variables:
cp .env.example .env.local
Then edit
.env.localwith your credentials:GEMINI_API_KEY=your_gemini_api_key NEXT_PUBLIC_SUPABASE_URL=your_supabase_url NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY=your_supabase_publishable_key NEXT_PUBLIC_URL=http://localhost:3000 NEXT_PUBLIC_BRAND_NAME=Your Event Name
-
Set up Supabase database:
- Create a new Supabase project
- Run the SQL from
supabase/schema.sqlin the SQL Editor - This creates the
twitter_handlestable with proper indexes and policies
-
Run the development server:
npm run dev
-
Open http://localhost:3000 in your browser
Edit tailwind.config.ts:
colors: {
'brand-primary': '#YOUR_COLOR',
'brand-secondary': '#YOUR_COLOR',
// ...
}Also update BRAND_COLORS in lib/gemini-api.ts to match.
Set NEXT_PUBLIC_BRAND_NAME in your .env.local file, or update it in the code.
Edit the components in components/ and app/page.tsx to change UI text and messaging.
Parasol-Tarot/
├── app/
│ ├── api/
│ │ ├── generate-outfit/ # Main tarot card generation endpoint
│ │ ├── resolve-identity/ # Twitter avatar fetching
│ │ └── og-image/ # Open Graph images
│ ├── outfit/[handle]/ # Shareable tarot card pages
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Main page
│ └── globals.css # Global styles
├── components/
│ ├── HandleInput.tsx # Twitter handle input
│ ├── LoadingState.tsx # Loading animations
│ ├── PlatformSelector.tsx # Platform UI
│ └── ResultsDisplay.tsx # Results display
├── lib/
│ ├── gemini-api.ts # Gemini API client
│ ├── supabase.ts # Supabase client
│ └── utils.ts # Utility functions
├── supabase/
│ └── schema.sql # Database schema
└── package.json
Fetches Twitter avatar for a handle.
Request:
{
"handle": "elonmusk",
"platform": "twitter"
}Response:
{
"success": true,
"profile": {
"id": "elonmusk",
"displayName": "elonmusk",
"imageUrl": "https://..."
}
}Generates a tarot card from an avatar image.
Request:
{
"imageUrl": "https://avatar-url.com/image.jpg",
"username": "elonmusk"
}Response:
{
"success": true,
"image": "base64_image_data"
}Returns tarot card image for Open Graph/social sharing (currently returns 404 as images are not cached).
- Push your code to GitHub
- Import project in Vercel
- Add environment variables in Vercel dashboard
- Deploy!
The app can be deployed to any platform that supports Next.js:
- Netlify
- Railway
- AWS Amplify
- etc.
Make sure to set all environment variables in your deployment platform.
- User enters Twitter handle → Frontend calls
/api/resolve-identity - Fetch avatar → Uses Unavatar.io to get profile picture
- Generate tarot card → Sends image to Gemini API for background removal and processing
- Add glow effect → Sharp adds a luminous glow around the portrait
- Composite on card → Portrait is composited onto tarot card background
- Save handle → Stores Twitter handle in Supabase database
- Display result → Shows generated tarot card with download/share options
| Variable | Description | Required |
|---|---|---|
GEMINI_API_KEY |
Google Gemini API key | Yes |
NEXT_PUBLIC_SUPABASE_URL |
Supabase project URL | Yes |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY |
Supabase publishable/default key | Yes |
NEXT_PUBLIC_URL |
Your app URL (for OG images) | Yes |
NEXT_PUBLIC_BRAND_NAME |
Brand/event name | No |
- Make sure you've set the environment variable in
.env.local - Restart your dev server after adding env vars
- The Twitter account might be private or suspended
- Try a different handle
- Use the upload feature as a fallback
- Check your Gemini API key is valid
- Check API quota/limits
- Try again (sometimes API has temporary issues)
MIT
Built with: