npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@quasarbright/projection

v1.0.3

Published

A static site generator that creates a beautiful, interactive gallery to showcase your coding projects. Features search, filtering, tags, responsive design, and an admin UI.

Readme

Projection

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

screenshot

✨ Features

  • 🖥️ 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)

📋 Table of Contents

📦 Installation

Requirements

  • Node.js 14.0.0 or higher

Install from npm

npm install -g @quasarbright/projection

Install from Source

# 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 link

Now you can use the projection command from anywhere on your system!

🚀 Quick Start

1. Initialize a New Project

# Create a new directory for your portfolio
mkdir my-portfolio
cd my-portfolio

# Initialize with sample files
projection init

This creates:

  • projects.yaml - Sample project data
  • projection.config.json - Configuration file with defaults
  • .gitignore - Git ignore patterns
  • README.md - Quick start guide

2. Edit Your Projects

Option A: Use the Admin Interface (Recommended)

projection admin

Opens 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: true

3. Start Development Server

projection dev

This will:

  • Build your site
  • Start a local server at http://localhost:8080
  • Watch for changes and auto-reload
  • Open your browser automatically

4. Build for Production

projection build

Your site will be generated in the dist/ directory, ready for deployment.

🖥️ Admin Interface

Projection includes a powerful web-based admin interface that makes managing your portfolio easier than editing files directly.

Starting the Admin Interface

projection admin

This opens a local web server at http://localhost:3000 with a full-featured admin UI.

Features

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

⚙️ Configuration

Configuration File

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:

  1. Command-line --config option
  2. projection.config.json in current directory
  3. Default configuration

projection.config.json

JSON format configuration file:

{
  "title": "My Projects",
  "description": "A showcase of my coding projects",
  "baseUrl": "./",
  "dynamicBackgrounds": [],
  "customStyles": null,
  "customScripts": null,
  "output": "dist"
}

Configuration Options

| 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 |

Editing Configuration

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.

Path Resolution

The baseUrl is used to resolve relative paths in your project data:

  • Relative paths (./path, ../path, filename) → Resolved relative to baseUrl
  • 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://...

🎨 Dynamic Backgrounds

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.

What are Dynamic Backgrounds?

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.

Managing Dynamic Backgrounds

Option A: Admin Interface (Recommended)

  1. Open the admin interface: projection admin
  2. Click the Settings button
  3. Navigate to the Dynamic Backgrounds tab
  4. Add background URLs with live preview
  5. 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"
  ]
}

Background Requirements

Your background pages should:

  1. Be full-screen - Fill the entire viewport
  2. Work in an iframe - Not blocked by X-Frame-Options
  3. Be performant - Lightweight animations that don't slow down the site

Best Practices

  1. Test performance - Ensure backgrounds don't slow down your site
  2. Keep it subtle - Backgrounds should enhance, not distract from your projects
  3. Consider accessibility - Avoid flashing or rapidly moving elements
  4. Mobile-friendly - Test on mobile devices for performance

📊 Project Data Format

Supported Formats

Projection automatically detects and reads project data from:

  1. projects.yaml (recommended)
  2. projects.yml
  3. projects.json

YAML Format (Recommended)

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"

JSON Format

{
  "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
    }
  ]
}

Project Fields

| 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) |

Field Validation Rules

Project ID (id)

  • 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

Creation Date (creationDate)

  • 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 zeros

🎨 Customization

Custom Styles

You can override the default styles by creating a styles/ directory in your project:

mkdir styles
# Add your custom CSS files

Directory 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 scheme
  • cards.css - Project card styling, 3D hover effects, background images
  • modal.css - Modal styling (for future use)

Custom Scripts

Similarly, you can override JavaScript functionality:

mkdir scripts
# Add your custom JavaScript files

Default scripts included:

  • search.js - Real-time search functionality
  • filter.js - Tag filtering and sorting
  • modal.js - Modal functionality (for future use)
  • dynamic-background.js - Dynamic background effects

Custom Assets

Place additional assets in an assets/ directory:

mkdir assets
# Add favicon, images, etc.

Template Resolution

Projection uses this priority for templates:

  1. User custom files in your project directory (styles/, scripts/, assets/)
  2. 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

🔧 Troubleshooting

Build Fails with "Projects file not found"

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 init

Invalid Project ID Error

Problem: 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"

Dev Server Port Already in Use

Problem: Port 8080 is already in use.

Solution:

# Use a different port
projection dev --port 3000

Changes Not Reflecting in Browser

Problem: Browser shows old content after changes.

Solution:

  1. Make sure dev server is running (projection dev)
  2. Check console for rebuild messages
  3. Hard refresh browser (Ctrl+Shift+R or Cmd+Shift+R)
  4. Clear browser cache

Missing Thumbnails

Problem: Project thumbnails not showing.

Solution:

  1. Check that thumbnailLink paths are correct
  2. Verify images exist at specified paths
  3. Run projection dev and use inspect element to check the img src on the card. You may need to update thumbnailLink or baseUrl.

Build Output Directory Not Created

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 -la

🚢 Deployment

The generated dist/ directory contains everything needed for deployment.

Deploying to GitHub Pages

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.

Quick Start

# Deploy your site in one command
projection deploy

That's it! Your site will be built and deployed to GitHub Pages automatically.

Prerequisites

Before deploying, make sure you have:

  1. Git installed on your system
  2. A Git repository initialized in your project:
    git init
    git add .
    git commit -m "Initial commit"
  3. A remote repository configured (usually on GitHub):
    git remote add origin https://github.com/username/repository-name.git

Step-by-Step Deployment

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 baseUrl is important for GitHub Pages if you're linking to other repos' pages.

2. Deploy your site

projection deploy

This command will:

  • ✅ Validate your Git setup
  • ✅ Build your site with the correct base URL
  • ✅ Create/update the gh-pages branch
  • ✅ Push your site to GitHub
  • ✅ Display your GitHub Pages URL

3. Enable GitHub Pages (first time only)

After your first deployment:

  1. Go to your repository on GitHub
  2. Click SettingsPages
  3. Under Source, select:
    • Branch: gh-pages
    • Folder: / (root)
  4. Click Save

Your site will be live at https://username.github.io/repository-name/ within a few minutes!

Configuration Options

In projection.config.json
{
  "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")
Command-Line Options
# 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 --force

Examples for Different Repository Types

Example 1: Project Repository (most common)

Repository: https://github.com/username/my-portfolio

Configuration:

{
  "title": "My Portfolio",
  "baseUrl": "/my-portfolio/"
}

Deploy:

projection deploy

Result: Site live at https://username.github.io/my-portfolio/

Example 2: Custom Domain

Repository: https://github.com/username/portfolio

Configuration:

{
  "title": "My Portfolio",
  "baseUrl": "/",
  "homepage": "portfolio.example.com"
}

Notes:

  • Use baseUrl: "/" for custom domains (root path)
  • The homepage field creates a CNAME file for your custom domain

Deploy:

projection deploy

DNS Setup (required for custom domains):

  1. Add a CNAME record pointing to username.github.io
  2. Or add A records pointing to GitHub's IPs:
    • 185.199.108.153
    • 185.199.109.153
    • 185.199.110.153
    • 185.199.111.153

Result: Site live at https://portfolio.example.com/

Troubleshooting Deployment

"Git is not installed"

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 git
"Not a git repository"

Problem: Your project is not a Git repository.

Solution:

# Initialize Git repository
git init
git add .
git commit -m "Initial commit"
"No git remote found"

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 -v
"Authentication failed"

Problem: Git cannot authenticate with GitHub.

Solution:

https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/about-authentication-to-github#authenticating-with-the-command-line

"Site not updating after deployment"

Problem: GitHub Pages shows old content after deployment.

Solution:

  1. Wait a few minutes - GitHub Pages can take 1-10 minutes to update
  2. Check GitHub Actions - Go to your repository → Actions tab to see build status
  3. Hard refresh browser - Press Ctrl+Shift+R (or Cmd+Shift+R on Mac)
  4. Verify gh-pages branch - Check that the branch has your latest changes
  5. Check GitHub Pages settings - Ensure it's configured to use the gh-pages branch
"404 errors for assets (CSS, images)"

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 img for the thumbnail, and look at its src attribute. Make sure it is correct. You may need to adjust baseurl.
"Custom domain not working"

Problem: Custom domain shows 404 or doesn't resolve.

Solution:

  1. Verify CNAME file exists:

    # Check gh-pages branch for CNAME file
    git checkout gh-pages
    cat CNAME  # Should contain your domain
    git checkout main
  2. 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.com to verify DNS
  3. Configure in GitHub:

    • Go to Settings → Pages
    • Enter your custom domain
    • Enable "Enforce HTTPS" (after DNS propagates)
  4. Update your config:

    {
      baseUrl: "/",
      homepage: "portfolio.example.com",
    };
"Build fails during deployment"

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 --clean

📁 Project Structure

my-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/

🤝 Contributing

Contributions are welcome! Here's how you can help:

  1. Report bugs - Open an issue with details and reproduction steps
  2. Suggest features - Share your ideas for improvements
  3. Submit pull requests - Fix bugs or add features

Development Setup

# 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 link

Creating a test portfolio

cd ../
mkdir projection-test
cd projection-test
projection init
projection admin

Running Tests

# Run all tests
npm test

# Run tests in watch mode
npm run test:watch

# Run specific test file
npm test -- config.test.ts

📄 License

MIT License - see LICENSE file for details.

🔗 Links

  • 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.