assets/js/ — Client-Side JavaScript

All JavaScript is vanilla ES5/ES6 — no framework, no build step. Scripts are loaded at the bottom of _layouts/default.html (or the specific layout that needs them). Each module is self-contained and initializes on DOMContentLoaded or via an IIFE.

wavesurfer.min.js is the only third-party library and is vendored directly (no CDN dependency).


Module Reference

Loaded on: every page (via default.html)

Handles all header interaction:


category-filter.js

Loaded on: blog index page (pages/blog.html)

Client-side filtering of the post list by category — no page reload required.

How it works: each .post-list-item has a data-categories="slug1 slug2" attribute set in the template. The script shows/hides items by checking whether the active slug appears in that space-separated list.


scroll-animations.js

Loaded on: every page (via default.html)

Uses IntersectionObserver to add the .animated class to section elements as they enter the viewport. CSS handles the actual fade-in transition via .animate-on-scroll and .animated.


hero-slideshow.js

Loaded on: homepage (if slideshow images are present)

Cycles through hero photo images with crossfade transitions. Configuration comes from data-interval and data-transition attributes on .hero-slideshow, which are set from _data/site.yml via Liquid.

To change timing: edit bio.hero_slideshow_interval and bio.hero_slideshow_transition in _data/site.yml.


Loaded on: homepage (if a [data-featured-carousel] element exists)

Infinite-loop carousel for the featured work section.


card-tilt.js

Loaded on: every page with .card elements

Adds a cursor-reactive 3D tilt and spotlight glare overlay to all .card elements.


portfolio-expand.js

Loaded on: homepage and /portfolio/ page

Collapses portfolio grids to two visible rows and adds a “See more” / “See less” toggle button. Row boundaries are calculated from offsetTop values, so it works with any grid column count.


shuffle-grids.js

Loaded on: homepage (or any page with .auto-grid)

Randomly shuffles cards within each .auto-grid on page load. Featured cards (.card--featured) are always kept first; the rest are shuffled.


pill-marquee.js

Loaded on: project/performance cards with .card-pills-track

Detects when a pill row overflows its container and adds .is-overflowing to the track. CSS then activates a horizontal scroll marquee animation on hover. Re-runs on window resize.


gallery.js

Loaded on: project and performance detail pages

Two behaviors:

  1. Shuffle — randomizes the order of gallery images on page load
  2. Lightbox — clicking a gallery image opens a full-screen overlay with prev/next navigation and keyboard support (arrow keys, Escape to close)

performance-gallery.js

Loaded on: pages with .performance-card-image--gallery elements

For performance cards that have multiple images:

  1. On page load, picks a random image from data-images (JSON array) and renders it as the card face
  2. On click (or Enter/Space), opens a full-screen lightbox the user can cycle through
  3. Shows a loading spinner while images load; nav buttons are disabled during load with an automatic timeout fallback

vo-player.js

Loaded on: pages with VO clip cards

Lazy-initializes WaveSurfer.js v6 for voice-over clip playback.


wavesurfer.min.js

Third-party library (WaveSurfer.js v6), vendored to avoid a CDN dependency. Do not edit this file. To upgrade, replace with the new minified build from the WaveSurfer.js releases.


Loading a Script

Scripts are referenced at the bottom of the relevant layout file. To add a new script to every page, add it to _layouts/default.html. For page-specific scripts, add the <script> tag to the specific layout (e.g. _layouts/project.html).

<script src="/assets/js/my-module.js" defer></script>

Use defer unless the script must run before the DOM is parsed.