CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

This is a Hugo academic website (Wowchemy/Hugo Blox theme) at /Users/max/Library/CloudStorage/Dropbox/TheFuerstLab/. Blog posts live in content/post/<date>-<slug>/ directories.

Site Structure

  • /config/_default/ - Hugo configuration (config.yaml, params.yaml, menus.yaml)
  • /layouts/partials/ - Custom template partials (custom_css.html, custom_js.html, custom_head.html)
  • /layouts/shortcodes/ - Custom Hugo shortcodes
  • /assets/scss/custom.scss - Global custom SCSS (compiled via custom_css.html)
  • /content/post/ - Blog posts, each in its own directory with index.md

How Custom JS/CSS Works in Posts

Posts can include inline <style> and <script> tags directly in their index.md files. Hugo renders these as raw HTML. This is the primary pattern for interactive/scrollable posts - all CSS and JS lives in the post’s index.md.

Global styles go in /assets/scss/custom.scss. Global JS goes in /layouts/partials/custom_js.html.

Theme Support

The site uses Wowchemy’s light/dark theme system:

  • Theme state: localStorage.getItem("wcTheme") (“1” = dark, else light)
  • Apply via: document.documentElement.setAttribute("data-wc-theme", mode)
  • Listen for toggles: click events on .js-set-theme-dark, .js-set-theme-light, .js-set-theme-auto
  • Use CSS variables for theme-aware colors (see custom.scss for examples)

Existing Scrollable Post Pattern

See content/post/2025-12-03-how-to-ask-for-research-internship/ for a scroll-driven text reveal post.

See content/post/2026-02-03-test-scrollables/ for a scroll-driven video post with:

  • Frame-based video scrubbing (WebP image sequence, not <video> - much smoother)
  • <img> element for rendering (not canvas - better quality on Retina displays)
  • Scroll-to-frame mapping with configurable slow points and ease in/out
  • Text overlays with SVG connector lines loaded from overlays.json
  • prepare-video.sh script for converting video to optimized frame sequences

Key Architecture Decisions

  1. Frames not video: Extracting video to individual WebP frames and swapping <img>.src gives smooth scroll-driven playback without the lag of video seeking.
  2. <img> not <canvas>: Native <img> elements render at full Retina quality. Canvas-based rendering looked blurry on HiDPI displays.
  3. Full-viewport layout: Video container is position: fixed; width: 100vw; height: 100vh. Image uses min-width: 100vw; min-height: 100vh for cover-style scaling.
  4. Non-linear scroll mapping: A speed function with cosine curves creates smooth slow-down zones. Pre-computed lookup table with binary search for efficient frame lookup.
  5. Loading strategy: First frame loads and displays immediately. Scrolling is disabled (body overflow: hidden) until all frames are loaded. Subtle progress indicator in bottom-left corner.

Performance Notes

  • WebP frames are ~60% smaller than JPEG at comparable quality
  • Frame skipping (every Nth frame) can halve data load with minimal visual impact
  • prepare-video.sh auto-calculates skip factor to hit a target total size
  • FPS counter available for testing (can be removed for production)
  • On MacBook Pro, expect 55-60 FPS with 144 frames at 3000x1722

overlays.json Format

{
  "startFrame": 22,
  "endFrame": 35,
  "text": "Annotation text",
  "targetX": 1560,       // video pixel X coordinate
  "targetY": 840,        // video pixel Y coordinate
  "position": "right",   // left|right|top|bottom|top-left|top-right|bottom-left|bottom-right
  "lineLength": 180,     // pixels from target to text
  "lineType": "solid",   // solid|dashed|dotted
  "lineWidth": 1,
  "lineColor": "#ffffff",
  "dotRadius": 12,
  "dotStyle": "hollow",  // filled|hollow
  "dotStrokeWidth": 1.5  // for hollow dots
}

JS Configuration Variables (top of script in index.md)

  • SCROLL_LENGTH - Viewport heights to scroll through (higher = slower)
  • TOTAL_FRAMES - Auto-updated by prepare-video.sh
  • SLOW_POINTS - Array of { frame, strength, width } for smooth deceleration
  • EASE_IN / EASE_OUT - { frames, strength } for smooth start/end

Tools

  • ffmpeg is available for video/image conversion
  • Use -c:v libwebp (not default) when extracting WebP frames with ffmpeg, otherwise it creates animated WebP
  • Hugo dev server for local testing
Maximilian JLJ Fürst
Maximilian JLJ Fürst
Assistant Professor of Computational Protein Design

I research computational protein design and high-throughput protein engineering.