This repository contains the code for my personal portfolio website.
- Responsive design
- Project showcase
- AI-powered mascot customization using Google's Gemini API
- Dynamic UI elements
- Clone the repository
- Install dependencies:
npm install
- Create a
.env
file with your Gemini API key:GEMINI_API_KEY=your_api_key_here
- Start the server:
node server.js
- Open http://localhost:3000 in your browser
To test the mascot image generation functionality:
node scripts/test-image-generation.js
- Frontend: HTML, CSS, JavaScript
- Backend: Node.js, Express
- AI Integration: Google Gemini API
- Deployment: GitHub Actions, Google Cloud Run, GitHub Pages
This website uses a modern deployment setup leveraging GitHub Actions and Google Cloud Run for automated deployment and scalable hosting.
- Static frontend files are deployed to GitHub Pages
- The Gemini API server runs on Google Cloud Run
- GitHub Actions automates both deployment processes
The repository includes two GitHub Actions workflows:
-
Frontend Deployment (
frontend-deploy.yml
):name: Deploy Frontend on: push: branches: [main] paths: - 'public/**' - 'index.html' - 'styles/**' jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Deploy to GitHub Pages uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./
-
Backend Deployment (
backend-deploy.yml
):name: Deploy Backend on: push: branches: [main] paths: - 'server/**' - 'package.json' jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Cloud SDK uses: google-github-actions/setup-gcloud@v0 with: project_id: ${{ secrets.GCP_PROJECT_ID }} service_account_key: ${{ secrets.GCP_SA_KEY }} - name: Build and Deploy to Cloud Run run: | gcloud builds submit --tag gcr.io/${{ secrets.GCP_PROJECT_ID }}/gemini-server gcloud run deploy gemini-server \ --image gcr.io/${{ secrets.GCP_PROJECT_ID }}/gemini-server \ --platform managed \ --region us-central1 \ --allow-unauthenticated
-
GitHub Repository Settings:
- Enable GitHub Pages in repository settings
- Add required secrets:
GCP_PROJECT_ID
: Your Google Cloud project IDGCP_SA_KEY
: Service account key JSON for Google Cloud authentication
-
Google Cloud Setup:
- Create a new project
- Enable Cloud Run and Container Registry APIs
- Create a service account with required permissions:
- Cloud Run Admin
- Artifact Registry Admin
- Storage Admin
- Service Account User
- Service Usage Consumer
- Download service account key JSON
-
Environment Configuration:
- Add
GEMINI_API_KEY
to Cloud Run environment variables - Update frontend API endpoint in
scripts/gemini-mascot.js
to point to your Cloud Run service
- Add
- Automated Deployments: Changes to frontend or backend code automatically trigger deployments
- Scalable Backend: Cloud Run automatically scales based on demand
- Cost-Effective: Only pay for actual backend usage
- Secure: API keys and secrets are safely managed through GitHub Secrets and Cloud Run
- Separated Concerns: Frontend and backend can be deployed and scaled independently
This deployment setup provides a production-ready environment that's both scalable and maintainable. The separation of frontend and backend deployments allows for independent scaling and updates while maintaining a cohesive system through automated workflows.
The website features a 3D card carousel for displaying the mascot and AI-generated variations:
-
Card Management:
- Maximum of 5 AI-generated images stored
- Automatic persistence using localStorage
- Newest images added to the front of the carousel
- Cards rotate with smooth 3D transitions
-
Loading and Generation:
- Dedicated loading card with static noise effect
- Visual feedback during image generation
- The loading card appears at the front of the carousel
- Seamless replacement with the new image when ready
- Automatic error handling with visual feedback
-
Navigation and Interaction:
- Previous/Next buttons for card rotation
- Cards slide up and fade during transitions
- Controls visibility based on card count
- Click-to-enlarge lightbox support
- Markdown formatting for descriptions
-
Visual Style:
- Cards stack with visible depth effect
- Blur effects increasing with depth
- Dark mode support with adjusted shadows
- Responsive sizing across all device sizes
- Sharp shadow aesthetic matching site design
-
Performance Optimizations:
- Optimized canvas rendering for loading effects
- Debounced resize handling
- Efficient DOM manipulation
- Animation frame management
- Lazy initialization of components
To customize how the AI generates mascot outfits, modify the prompt in scripts/gemini-mascot.js
. Look for the prompt
constant:
const prompt = "Your custom prompt here";
The prompt should describe:
- The mascot's base appearance
- Desired outfit style changes
- Any specific fashion elements or aesthetics
- How to handle existing elements (like accessories)
To use your own mascot, you'll need to update several files:
-
Prepare your mascot images:
- Main display image (e.g., with background/scene)
- Use clear, high-quality images
- Recommended size: at least 512x512 pixels
- Format: PNG or JPEG
-
Place your images in the
assets/images
directory:- Save your main display image (e.g.,
YourMascot.jpg
) - Save your transparent version as
PolarBearTransparent4K.png
(or update the path in the files below)
- Save your main display image (e.g.,
-
Update the image paths in these files:
index.html
: Update the main display image<img src="assets/images/YourMascot.jpg" alt="Your Mascot Description" class="mascot">
server.js
: Update the AI generation image path (around line 50)const imagePath = 'assets/images/PolarBearTransparent4K.png';
scripts/test-image-generation.js
: Update the test script image pathconst imagePath = 'assets/images/PolarBearTransparent4K.png';
-
Adjust the prompt to match your mascot's characteristics
-
Test the image generation using the test script:
node scripts/test-image-generation.js
-
Image Size Considerations
- Keep mascot images at recommended size (512x512px)
- Larger images increase API response time and costs
- Smaller images may reduce generation quality
-
Rate Limiting
- Default cooldown period between generations
- Prevents API abuse and manages costs
- Adjust in
server.js
if needed:const RATE_LIMIT_MS = 5000; // 5 seconds between generations
-
Caching Strategy
- Generated outfits are cached server-side
- Reduces API calls and improves response times
- Configure cache size in
server.js
:const CACHE_SIZE = 10; // Number of recent generations to keep
-
Error Handling
- Graceful fallbacks when API is unavailable
- Automatic retries for failed generations
- User feedback through UI state changes
The website features a dynamic static noise background effect that can be customized by modifying parameters in scripts/static-background.js
. The effect includes both a normal state and an enhanced "magic mode" that activates during certain interactions.
To adjust the basic static effect, modify these parameters in the config
object:
const config = {
pixelSize: 1, // Size of each static pixel
density: 0.8, // Density of static dots
baseAlpha: 0.85, // Base opacity of static
alphaVariance: 0.25 // Random variance in opacity
};
The static effect automatically adapts to light/dark mode. Customize the intensity ranges:
const config = {
// Dark mode settings (bright dots on dark background)
darkIntensityMin: 30,
darkIntensityMax: 100,
// Light mode settings (dark dots on light background)
lightIntensityMin: 135,
lightIntensityMax: 200
};
When magic mode activates (during certain interactions), the static becomes more intense and colorful. Customize these effects:
const config = {
intenseDensity: 1.8, // Density during magic mode
intenseColor: [200, 120, 255], // Purple magic color [R,G,B]
transitionSpeed: 0.012 // Speed of transition to/from magic mode
};
### Magic Mode and Gemini Integration
The static loading effect is designed to enhance the user experience during Gemini AI image generation. When you click the Style Inspiration button to generate a new outfit for the mascot:
1. A loading card appears with a purple-tinted static effect
2. This visual feedback indicates that the AI is processing your request
3. The static effect continues until the new image is ready
4. Once the new image loads, the loading card and static effect are smoothly replaced
This creates a cohesive experience where the loading state provides clear visual feedback during AI interactions, making the website feel more dynamic and responsive.
### Performance Settings
Adjust performance-related parameters:
```javascript
const config = {
frameInterval: 45, // Milliseconds between frames (~20fps)
};
You can trigger the enhanced static effect from your JavaScript code:
// Enable magic mode
window.staticBackground.enableMagicMode();
// Disable magic mode
window.staticBackground.disableMagicMode();
The static background effect is designed to be performant while maintaining visual quality. Here are key considerations:
-
Frame Rate Control
- Default runs at ~20fps (45ms intervals) to balance smoothness and CPU usage
- Automatically pauses when tab is not visible
- Adjust
frameInterval
for different performance targets:const config = { frameInterval: 45, // Increase for better performance, decrease for smoother animation };
-
Density Scaling
- Static density automatically scales with screen size
- Adjust
density
andintenseDensity
for performance:const config = { density: 0.8, // Decrease for better performance intenseDensity: 1.8 // Decrease for better performance in magic mode };
-
Pixel Size Optimization
- Larger
pixelSize
values improve performance but reduce quality - Consider increasing on lower-end devices:
const config = { pixelSize: 1, // Increase to 2 or 3 for better performance };
- Larger
-
Dark Mode Optimizations
- Automatically reduces effects intensity in dark mode
- Fewer particles and lower opacity for better visibility and performance
- Static effect uses
requestAnimationFrame
for optimal performance - Fallback to simpler static effect on older browsers
- Automatically adjusts quality based on device capabilities
- Supports both mouse and touch interactions
-
API Endpoint Location
- Deploy Cloud Run backend in regions close to your users
- Use CDN for static assets
- Configure CORS appropriately for your deployment
-
Asset Loading
- Mascot images are lazy-loaded
- Static effect starts immediately while assets load
- Progressive enhancement approach