A modern, reusable static site generator that creates beautiful, interactive galleries to showcase your coding projects. Generate your portfolio site with a single command.
Here is an example of a portfolio site using Projection: https://quasarbright.github.io/portfolio/
And its source code: https://github.com/quasarbright/portfolio
- 🖥️ Web Admin Interface - Manage projects through an intuitive web UI with live preview
- 📦 Easy Installation - Install globally from source
- 🚀 Quick Setup - Initialize a new project in seconds
- 📱 Responsive Design - Works on desktop, tablet, and mobile
- 🔍 Search & Filter - Real-time search and tag-based filtering
- ⭐ Featured Projects - Highlight your best work
- 🏷️ Flexible Tagging - Organize projects with tags (ANY/ALL filtering)
- 🔥 Hot Reloading - Development server with automatic rebuild and refresh
- 🎨 Customizable - Override default styles and scripts
- 🚢 GitHub Pages Deployment - Deploy with a single command (or through the admin UI)
- Installation
- Quick Start
- Admin Interface
- Configuration
- Project Data Format
- Customization
- Troubleshooting
- Deployment
- Project Structure
- Contributing
- License
- Links
- Node.js 14.0.0 or higher
npm install -g @quasarbright/projection# Clone the repository
git clone https://github.com/quasarbright/projection.git
cd projection
# Install dependencies
npm install
# Build the project
npm run build
# Link globally (makes 'projection' command available)
npm linkNow you can use the projection command from anywhere on your system!
# Create a new directory for your portfolio
mkdir my-portfolio
cd my-portfolio
# Initialize with sample files
projection initThis creates:
projects.yaml- Sample project dataprojection.config.json- Configuration file with defaults.gitignore- Git ignore patternsREADME.md- Quick start guide
Option A: Use the Admin Interface (Recommended)
projection adminOpens a web-based editor at http://localhost:3000 where you can:
- Add, edit, and delete projects visually
- Upload project thumbnails
- See live preview of your portfolio
- Manage tags with autocomplete
Option B: Edit Files Directly
Edit projects.yaml to add your own projects:
projects:
- id: "my-awesome-project"
title: "My Awesome Project"
description: "A brief description of what this project does"
creationDate: "2024-01-15"
tags: ["web", "javascript"]
pageLink: "https://example.com/my-project"
sourceLink: "https://github.com/username/my-project"
thumbnailLink: "./screenshots/project.png"
featured: trueprojection devThis will:
- Build your site
- Start a local server at http://localhost:8080
- Watch for changes and auto-reload
- Open your browser automatically
projection buildYour site will be generated in the dist/ directory, ready for deployment.
Projection includes a powerful web-based admin interface that makes managing your portfolio easier than editing files directly.
projection adminThis opens a local web server at http://localhost:3000 with a full-featured admin UI.
Visual Project Editor
- Create, edit, and delete projects through an intuitive form interface
- Live preview of your portfolio as you make changes
- Real-time validation with helpful error messages
Image Management
- Upload project thumbnails directly through the UI
- Drag-and-drop image upload
- Automatic image optimization and storage
Tag Management
- Visual tag selector with autocomplete
- See tag usage counts across all projects
- Create new tags on the fly
Live Preview
- See your changes instantly in an embedded preview
- Click projects in the preview to edit them
- Test search and filtering in real-time
Smart Editing
- Form validation ensures data integrity
- Automatic ID generation from project titles
- Date picker for creation dates
- Toggle featured status with a checkbox
Projection uses a projection.config.json file for site configuration. This file is separate from your project data and can be edited through the admin interface or manually.
Configuration is loaded in this order:
- Command-line
--configoption projection.config.jsonin current directory- Default configuration
JSON format configuration file:
{
"title": "My Projects",
"description": "A showcase of my coding projects",
"baseUrl": "./",
"dynamicBackgrounds": [],
"customStyles": null,
"customScripts": null,
"output": "dist"
}| Option | Type | Default | Description |
|---|---|---|---|
title |
string | "My Projects" | Site title displayed in header |
description |
string | "A showcase of my coding projects" | Site description and meta description |
baseUrl |
string | "./" | Base URL for resolving relative paths |
dynamicBackgrounds |
string[] | [] | Array of background URLs (see Dynamic Backgrounds) |
customStyles |
string | null | Path to custom styles directory |
customScripts |
string | null | Path to custom scripts directory |
output |
string | "dist" | Output directory path |
Option A: Admin Interface (Recommended)
Use the Settings button in the admin interface to edit configuration through a user-friendly form with validation.
Option B: Edit Manually
Edit projection.config.json directly in your text editor.
The baseUrl is used to resolve relative paths in your project data:
- Relative paths (
./path,../path,filename) → Resolved relative tobaseUrl - Absolute paths (
/path) → Used as-is - Full URLs (
https://...) → Used as-is
Example:
// Config
baseUrl: "https://username.github.io/"
// Project data
pageLink: "./my-project/" // → https://username.github.io/my-project/
pageLink: "/absolute" // → /absolute
pageLink: "https://..." // → https://...Projection supports dynamic backgrounds that add visual interest to your portfolio. These are web pages (like p5.js sketches, animations, or visualizations) that display behind your project cards.
Dynamic backgrounds are full-screen web pages loaded in an iframe behind your portfolio content. Each time a visitor loads your site, one background is randomly selected from your list, creating a unique experience.
Option A: Admin Interface (Recommended)
- Open the admin interface:
projection admin - Click the Settings button
- Navigate to the Dynamic Backgrounds tab
- Add background URLs with live preview
- Test each background before saving
The admin interface provides:
- Live iframe previews of each background
- Visual status indicators (loaded/error)
- Click to expand and test backgrounds full-screen
Option B: Edit Configuration Manually
Add background URLs to your projection.config.json:
{
"title": "My Projects",
"description": "My portfolio",
"baseUrl": "./",
"dynamicBackgrounds": [
"https://example.com/background1",
"https://example.com/background2",
"https://example.com/background3"
]
}Your background pages should:
- Be full-screen - Fill the entire viewport
- Work in an iframe - Not blocked by X-Frame-Options
- Be performant - Lightweight animations that don't slow down the site
- Test performance - Ensure backgrounds don't slow down your site
- Keep it subtle - Backgrounds should enhance, not distract from your projects
- Consider accessibility - Avoid flashing or rapidly moving elements
- Mobile-friendly - Test on mobile devices for performance
Projection automatically detects and reads project data from:
projects.yaml(recommended)projects.ymlprojects.json
projects:
- id: "awesome-project"
title: "Awesome Project"
description: "This project does amazing things with modern web technologies"
creationDate: "2024-01-15"
tags: ["web", "javascript", "typescript"]
pageLink: "./awesome-project/"
sourceLink: "https://github.com/username/awesome-project"
thumbnailLink: "./screenshots/awesome.png"
featured: true
- id: "another-project"
title: "Another Project"
description: "A different project with different features"
creationDate: "2024-02-20"
tags: ["python", "data-science"]
pageLink: "https://example.com/another-project"
thumbnailLink: "./screenshots/another.png"{
"projects": [
{
"id": "awesome-project",
"title": "Awesome Project",
"description": "This project does amazing things",
"creationDate": "2024-01-15",
"tags": ["web", "javascript"],
"pageLink": "./awesome-project/",
"sourceLink": "https://github.com/username/awesome-project",
"thumbnailLink": "./screenshots/awesome.png",
"featured": true
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
id |
string | ✅ Yes | Unique identifier (must be valid URL slug: lowercase, alphanumeric, hyphens only) |
title |
string | ✅ Yes | Display name of the project |
description |
string | ✅ Yes | Project description (truncated with ellipsis on cards) |
creationDate |
string | ✅ Yes | ISO date string (YYYY-MM-DD format) |
tags |
string[] | ✅ Yes | Array of tags for categorization and filtering |
pageLink |
string | ✅ Yes | Primary link to the project (page, demo, or live site) |
sourceLink |
string | ❌ No | Link to source code repository (shows "Source Code" button) |
thumbnailLink |
string | ❌ No | Path or URL to project screenshot (used as card background) |
featured |
boolean | ❌ No | Highlight the project with special styling (border and badge) |
- Must be unique across all projects
- Must be a valid URL slug:
- Lowercase letters only
- Can contain numbers and hyphens
- Cannot start or end with a hyphen
- Pattern:
/^[a-z0-9]+(?:-[a-z0-9]+)*$/
Valid IDs:
id: "my-project"
id: "project-123"
id: "awesome-web-app"Invalid IDs:
id: "My-Project" # ❌ Contains uppercase
id: "-my-project" # ❌ Starts with hyphen
id: "my_project" # ❌ Contains underscore
id: "my project" # ❌ Contains space- Must be in ISO date format:
YYYY-MM-DD - Used for sorting projects by date
Valid dates:
creationDate: "2024-01-15"
creationDate: "2023-12-31"Invalid dates:
creationDate: "01/15/2024" # ❌ Wrong format
creationDate: "2024-1-5" # ❌ Missing leading zerosYou can override the default styles by creating a styles/ directory in your project:
mkdir styles
# Add your custom CSS filesDirectory structure:
my-portfolio/
├── styles/
│ ├── main.css # Override main styles
│ ├── cards.css # Override card styles
│ └── custom.css # Add your own styles
├── projects.yaml
└── projection.config.json
If the styles/ directory exists, Projection will use your custom styles instead of the bundled defaults. You can copy the default styles and modify them:
Default styles included:
main.css- Layout, theme, components, dark color schemecards.css- Project card styling, 3D hover effects, background imagesmodal.css- Modal styling (for future use)
Similarly, you can override JavaScript functionality:
mkdir scripts
# Add your custom JavaScript filesDefault scripts included:
search.js- Real-time search functionalityfilter.js- Tag filtering and sortingmodal.js- Modal functionality (for future use)dynamic-background.js- Dynamic background effects
Place additional assets in an assets/ directory:
mkdir assets
# Add favicon, images, etc.Projection uses this priority for templates:
- User custom files in your project directory (
styles/,scripts/,assets/) - Bundled defaults from the package
This allows you to:
- Use defaults out of the box
- Override specific files as needed
- Mix custom and default files
Problem: Projection can't find your project data file.
Solution:
# Make sure you have one of these files:
ls projects.yaml # or projects.yml or projects.json
# If not, initialize a new project:
projection initProblem: Project ID doesn't match the required format.
Solution: Project IDs must be valid URL slugs:
# ✅ Good
id: "my-awesome-project"
id: "project-123"
# ❌ Bad
id: "My Project" # Use: "my-project"
id: "project_name" # Use: "project-name"
id: "-my-project" # Use: "my-project"Problem: Port 8080 is already in use.
Solution:
# Use a different port
projection dev --port 3000Problem: Browser shows old content after changes.
Solution:
- Make sure dev server is running (
projection dev) - Check console for rebuild messages
- Hard refresh browser (Ctrl+Shift+R or Cmd+Shift+R)
- Clear browser cache
Problem: Project thumbnails not showing.
Solution:
- Check that
thumbnailLinkpaths are correct - Verify images exist at specified paths
- Run
projection devand use inspect element to check the img src on the card. You may need to updatethumbnailLinkorbaseUrl.
Problem: dist/ directory doesn't exist after build.
Solution:
# Check for build errors
projection build
# Try cleaning first
projection build --clean
# Check file permissions
ls -laThe generated dist/ directory contains everything needed for deployment.
Projection includes a built-in deploy command that makes deploying to GitHub Pages effortless. It automatically builds your site and publishes it to the gh-pages branch.
# Deploy your site in one command
projection deployThat's it! Your site will be built and deployed to GitHub Pages automatically.
Before deploying, make sure you have:
- Git installed on your system
- A Git repository initialized in your project:
git init git add . git commit -m "Initial commit"
- A remote repository configured (usually on GitHub):
git remote add origin https://github.com/username/repository-name.git
1. Configure your site for GitHub Pages
Add a baseUrl to your projection.config.json:
{
"title": "My Portfolio",
"description": "My awesome projects",
"baseUrl": "/"
}Note: The
baseUrlis important for GitHub Pages if you're linking to other repos' pages.
2. Deploy your site
projection deployThis command will:
- ✅ Validate your Git setup
- ✅ Build your site with the correct base URL
- ✅ Create/update the
gh-pagesbranch - ✅ Push your site to GitHub
- ✅ Display your GitHub Pages URL
3. Enable GitHub Pages (first time only)
After your first deployment:
- Go to your repository on GitHub
- Click Settings → Pages
- Under Source, select:
- Branch:
gh-pages - Folder:
/ (root)
- Branch:
- Click Save
Your site will be live at https://username.github.io/repository-name/ within a few minutes!
{
"baseUrl": "/repository-name/",
"homepage": "portfolio.example.com",
"deployBranch": "gh-pages"
}Configuration notes:
baseUrl- Required for GitHub Pages (use your repository name)homepage- Optional: Custom domain (creates CNAME file)deployBranch- Optional: Custom deployment branch (defaults to "gh-pages")
# Deploy to a custom branch
projection deploy --branch main
# Custom commit message
projection deploy --message "Update portfolio with new projects"
# Use a different Git remote
projection deploy --remote upstream
# Skip the build step (use existing dist/)
projection deploy --no-build
# Deploy from a custom directory
projection deploy --dir build
# Simulate deployment without pushing
projection deploy --dry-run
# Force push (overwrites remote history)
projection deploy --forceRepository: https://github.com/username/my-portfolio
Configuration:
{
"title": "My Portfolio",
"baseUrl": "/my-portfolio/"
}Deploy:
projection deployResult: Site live at https://username.github.io/my-portfolio/
Repository: https://github.com/username/portfolio
Configuration:
{
"title": "My Portfolio",
"baseUrl": "/",
"homepage": "portfolio.example.com"
}Notes:
- Use
baseUrl: "/"for custom domains (root path) - The
homepagefield creates a CNAME file for your custom domain
Deploy:
projection deployDNS Setup (required for custom domains):
- Add a CNAME record pointing to
username.github.io - Or add A records pointing to GitHub's IPs:
185.199.108.153185.199.109.153185.199.110.153185.199.111.153
Result: Site live at https://portfolio.example.com/
Problem: Git is not found on your system.
Solution:
# Install Git
# macOS (with Homebrew):
brew install git
# Windows: Download from https://git-scm.com/
# Linux (Ubuntu/Debian):
sudo apt-get install gitProblem: Your project is not a Git repository.
Solution:
# Initialize Git repository
git init
git add .
git commit -m "Initial commit"Problem: No remote repository is configured.
Solution:
# Add a remote (replace with your repository URL)
git remote add origin https://github.com/username/repository-name.git
# Verify remote was added
git remote -vProblem: Git cannot authenticate with GitHub.
Solution:
Problem: GitHub Pages shows old content after deployment.
Solution:
- Wait a few minutes - GitHub Pages can take 1-10 minutes to update
- Check GitHub Actions - Go to your repository → Actions tab to see build status
- Hard refresh browser - Press Ctrl+Shift+R (or Cmd+Shift+R on Mac)
- Verify gh-pages branch - Check that the branch has your latest changes
- Check GitHub Pages settings - Ensure it's configured to use the
gh-pagesbranch
Problem: Your site loads but CSS and images are broken.
Solution: Check your baseUrl configuration:
- Make sure it has a trailing slash
- inspect the project's card, find the
imgfor the thumbnail, and look at itssrcattribute. Make sure it is correct. You may need to adjustbaseurl.
Problem: Custom domain shows 404 or doesn't resolve.
Solution:
-
Verify CNAME file exists:
# Check gh-pages branch for CNAME file git checkout gh-pages cat CNAME # Should contain your domain git checkout main
-
Check DNS configuration:
- CNAME record should point to
username.github.io - DNS changes can take up to 48 hours to propagate
- Use
dig portfolio.example.comto verify DNS
- CNAME record should point to
-
Configure in GitHub:
- Go to Settings → Pages
- Enter your custom domain
- Enable "Enforce HTTPS" (after DNS propagates)
-
Update your config:
{ baseUrl: "/", homepage: "portfolio.example.com", };
Problem: The build step fails before deployment.
Solution:
# Test build locally first
projection build
# Check for errors in your projects.yaml
# Common issues:
# - Invalid project IDs
# - Missing required fields
# - Invalid date formats
# If build works locally, try:
projection deploy --cleanmy-portfolio/
├── projects.yaml # Your project data
├── projection.config.json # Configuration (optional)
├── styles/ # Custom styles (optional)
│ ├── main.css
│ └── custom.css
├── scripts/ # Custom scripts (optional)
│ └── custom.js
├── assets/ # Static assets (optional)
│ └── favicon.ico
├── screenshots/ # Project thumbnails
│ ├── project1.png
│ └── project2.png
└── dist/ # Generated site (created by build)
├── index.html
├── styles/
├── scripts/
└── assets/
Contributions are welcome! Here's how you can help:
- Report bugs - Open an issue with details and reproduction steps
- Suggest features - Share your ideas for improvements
- Submit pull requests - Fix bugs or add features
# Clone the repository
git clone https://github.com/quasarbright/projection.git
cd projection
# Install dependencies
npm install
# Build the project
npm run build
# Run tests
npm test
# Make projection command accessible
npm linkCreating a test portfolio
cd ../
mkdir projection-test
cd projection-test
projection init
projection admin# Run all tests
npm test
# Run tests in watch mode
npm run test:watch
# Run specific test file
npm test -- config.test.tsMIT License - see LICENSE file for details.
- GitHub Repository: https://github.com/quasarbright/projection
- Live Demo: https://quasarbright.github.io/portfolio/
- Author: Mike Delmonaco
- Issues: https://github.com/quasarbright/projection/issues
Need help? Open an issue on GitHub or check the troubleshooting section.
