Skip to content

About

Github Pages Personal Resume

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

Kellen Stuart Portfolio

This repository contains a React 19 single-page portfolio/resume app built with Vite.

Requirements

  • Node.js 24.x LTS (project pin: 24.21.0 in .nvmrc)
  • npm 12.x (project pin: 12.0.2 in package.json)
  • Git
  • Optional: ImageMagick, for stripping image metadata when the media metadata check fails
  • Optional: metaflac, for stripping FLAC metadata when the media metadata check fails

Scripts

Development

  • npm run dev (or npm start): start the local Vite dev server at http://localhost:5173
  • npm run build: create a production build in dist/ and copy dist/index.html to dist/404.html
  • npm run preview: preview the production build locally
  • npm run test:jam: validate jam filtering, catalog metadata, and chart authoring without starting a server
  • npm run check:media-metadata: check tracked and untracked media files for image and FLAC metadata
  • npm run check:image-metadata: compatibility alias for npm run check:media-metadata
  • npm run setup:hooks: configure this local clone to use the repo's Git hooks from .githooks/
  • npm run generate:resume-pdf: use Playwright + headless Chromium to render /print-resume?mode=pdf into dist/Kellen-Stuart-Resume.pdf (requires dist/ to exist)

Deploy

  • npm run predeploy: run the production build and generate dist/Kellen-Stuart-Resume.pdf
  • npm run deploy: publish dist/ using gh-pages (runs predeploy automatically)

Install

Use the Node.js version in .nvmrc and npm version in package.json. Dependency installation is performed by the operator, as required by AGENTS.md.

npm ci
npm run setup:hooks
npm run check:media-metadata

After changing dependency versions in package.json, run npm install to update package-lock.json and the installed packages, then validate with npm run build and npm run check:media-metadata. Commit both package files together. After a Playwright upgrade, run npx playwright install chromium to install its matching browser before testing resume PDF generation.

Notes

  • Static assets are served from public/.
  • Routing is handled client-side with react-router.
  • The build includes a 404.html copy for static hosting fallback behavior.
  • If Playwright browser binaries are missing in your environment, run npx playwright install chromium.
  • On Linux runners/workstations missing shared libraries, run npx playwright install --with-deps chromium.

Jam Song Metadata

For the step-by-step process of adding a chart, including chord/lyric alignment, important voicings, rhythm notation, and validation, see Authoring jam charts. Song-specific content belongs in src/data/charts/; jamSongs.js holds catalog metadata and associates it with those chart modules.

Edit songs in src/data/jamSongs.js. People, genres, and Yousician availability have their own fields; practice and descriptive labels remain in tags.

playedWith: [musicians.kaylee, musicians.casey],
genres: ["punk"],
hasYousician: true,
tags: [jamTags.needsWork, jamTags.soloLearned],
  • playedWith records people you've played the song with. Use references such as musicians.kaylee instead of quoted IDs. To add someone, define their stable ID in musicians and their display name in jamMusicians. This is jam history, not a required lineup or a claim that everyone currently remembers the song.
  • genres accepts multiple IDs from jamGenres, such as "punk", "country", "classic rock", and "psychedelic". Leave it empty when unspecified.
  • hasYousician displays Available when true and Not Available when false. The display reflects the catalog flag. Existing Yousician tags were carried over as true; availability has not been independently checked.
  • tags uses jamTags for practice and descriptions such as Acoustic or Open Jam. Needs Work and Stage Ready can coexist; they have not been reduced to a single readiness value. Solo progress remains separate.
  • Catalog songs default to empty people/genre/tag arrays and hasYousician: false when these fields are omitted. Tuning, musical key, capo, and chart data keep their existing fields.

On /jam, click names under Played with to find songs you've played with every selected person. Each additional person narrows the list; click a selected name again to remove it. Selected buttons show a checkmark. There is no matching mode to choose. Genre, Guitar Tuning, Yousician, and chart filters match any selected option within their group. Different groups narrow each other. Practice and other tags require every selected tag.

The main filter groups appear in this order: Played with, Guitar Tuning, Genre, and Chart. Stage Ready is a standalone toggle immediately below them. More filters contains Practice, Yousician, and Other Tags, in that order; Stage Ready is not repeated inside Practice and does not count toward the More filters selection count. Selected filters remain visible and removable even when that section is collapsed. Song cards show guitar tuning, key, and Stage Ready first. More song details shows compact clickable lists for Played with, Genres, Practice Notes, and Other Tags, plus additional song facts. Yousician appears last as plain Available / Not Available text. Chart availability remains in the card footer and main Chart filters. Search includes names, genres, practice tags, and song details. Musical key is informational only: it appears as a plain label on song cards and is excluded from filters and the search metadata. Guitar tuning uses the same plain-label style directly below the key; filter it using the Guitar Tuning controls in the main filter section.

The print view at /jam/print groups songs alphabetically by artist, then by song title. Song lines are indented without numbering and show Title - 🎸 Guitar tuning - ♫ Musical key, with 🤘 for Ready to rock (Stage Ready). Missing values display Tuning TBD or Key TBD. The sheet uses two columns, with a single column on narrow screens.

Run npm run test:jam and npm run build after changing filter logic. For a manual smoke test, select two people and verify each song lists both, then deselect one and confirm the list broadens. Select two genres or tunings, try the Yousician filter, and clear the selections. Check the expandable controls on a phone-sized viewport and confirm the Rooster chart and print list still open.

Image Metadata Guard

The repo includes a pre-push hook at .githooks/pre-push that checks media metadata before anything is pushed.

Fresh clones need one local Git setting because core.hooksPath is not committed with the repo:

npm run setup:hooks

The hook itself only requires Git and Node. ImageMagick is optional but recommended because it is the easiest way to clean an image that fails the check. metaflac is optional but recommended for cleaning FLAC files.

Typical cleanup commands:

magick input.png -strip output.png
magick input.webp -strip output.webp
magick input.jpg -auto-orient -strip output.jpg
metaflac --dont-use-padding --remove-all input.flac

On ImageMagick 6, use convert instead of magick.

Blog Photos

Blog posts support both hero photos and inline photos.

  1. Put image files in public/blog/<post-slug>/, for example public/blog/my-post/trail.webp.
  2. Add an optional heroImage object in src/data/blogPosts.js:
heroImage: {
  src: "/blog/my-post/trail.webp",
  alt: "Backpacking trail at sunrise",
  caption: "Day 2, near treeline.",
}
  1. To insert inline photos inside a post component, import and use BlogImage:
import BlogImage from "../components/blog/BlogImage";

<BlogImage
  src="/blog/my-post/camp.webp"
  alt="Camp setup near an alpine lake"
  caption="Final campsite before summit day."
/>;

Blog Updates

Posts can track publish date, last-updated date, and an optional update log.

  1. Add lastUpdated and updates in src/data/blogPosts.js:
{
  slug: "my-post",
  title: "My Post",
  date: "2026-03-01",
  lastUpdated: "2026-06-15",
  updates: [
    { date: "2026-04-03", note: "Added new photos." },
    { date: "2026-06-15", note: "Added audio recordings and notes." },
  ],
}
  1. The blog template will automatically render:
  • Published <date>
  • Last updated <date> (when different from publish date)
  • an Updates section when updates has entries

Blog Recordings

To embed recordings in a post, use BlogAudio:

import BlogAudio from "../components/blog/BlogAudio";

<BlogAudio
  src="/blog/my-post/riff-demo-1.mp3"
  title="Riff Demo 1"
  caption="LA30BL, Sabbra Cadabra at 18V, C# standard."
/>;

Store audio files under public/blog/<post-slug>/ so they are available as static assets.

Local PDF Download Testing

To make the Download PDF button return a real PDF locally:

  1. Install Playwright Chromium: npx playwright install chromium
  2. Build + generate the PDF artifact: npm run predeploy
  3. Serve from dist/: npm run preview
  4. Test Download PDF in the preview app

npm run dev is not sufficient for this test because it does not serve the generated dist/Kellen-Stuart-Resume.pdf artifact.

About

Github Pages Personal Resume

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages