Local Development Guide
This is a Jekyll-based personal homepage. Below are instructions for building and previewing it locally on macOS.
Prerequisites
- Podman (or Docker) — used to run Jekyll in a container, avoiding the need to install Ruby/Bundler natively
- Python 3 — used to serve the built static site for preview
Check Podman availability:
podman --version # should show 5.x+
If you use Docker instead of Podman, simply replace podman with docker in all commands below.
Build
Run Jekyll build inside a container:
podman run --rm \
--volume="$PWD:/srv/jekyll:Z" \
jekyll/jekyll:4.2.2 \
sh -c "bundle install 2>&1 | tail -1 && bundle exec jekyll build"
This generates the static site into the _site/ directory. Build takes ~30-40 seconds.
Preview
After building, serve the _site/ directory with Python’s built-in HTTP server:
cd _site
python3 -m http.server 4000
Then open http://localhost:4000 in your browser.
Press Ctrl+C to stop the server.
Quick Script (Build + Preview)
You can also use the one-liner:
podman run --rm --volume="$PWD:/srv/jekyll:Z" jekyll/jekyll:4.2.2 \
sh -c "bundle install 2>&1 | tail -1 && bundle exec jekyll build" \
&& cd _site && python3 -m http.server 4000
Notes
- Podman on macOS runs via a VM (libkrun). If
podman machineis not started, run:podman machine start - amd64 emulation warning:
jekyll/jekyll:4.2.2is a linux/amd64 image. On Apple Silicon (arm64), Podman will emulate it via QEMU. This works but is slower. The warningimage platform does not matchis harmless. jekyll servedoesn’t work in this container due to Ruby 3.x removingwebrickfrom the standard library. Usingjekyll build+ Python HTTP server is the workaround.- Port conflict: If port 4000 is already in use, change the port number (e.g.,
python3 -m http.server 4001).
Troubleshooting
| Problem | Solution |
|---|---|
Permission denied @ dir_s_mkdir - _site |
Run mkdir -p _site && chmod 777 _site before building |
podman machine not running |
Run podman machine start |
| Port 4000 already in use | Use a different port: python3 -m http.server 4001 |
Build fails with no implicit conversion of Hash into Integer |
Don’t use --force_polling with jekyll serve; use jekyll build instead |
Image Optimization
Teaser images are displayed at max 400px width in the browser, but source images can be much larger. To keep page load fast, images should be resized to max 800px wide (2x for retina displays) and compressed.
Method: macOS sips (built-in, no installation needed)
# Resize a single image to max 800px wide (keeps aspect ratio)
sips --resampleWidth 800 --setProperty formatOptions best images/papers/example.png
# Batch resize all PNGs larger than 500KB in papers/
for f in images/papers/*.png; do
kb=$(wc -c < "$f" | awk '{printf "%d", $1/1024}')
if [ $kb -gt 500 ]; then
echo "Compressing $(basename $f) ($kb KB)..."
# Back up original first
cp "$f" images/papers/originals/$(basename $f)
# Resize and re-encode
sips --resampleWidth 800 --setProperty formatOptions best "$f" --out "$f"
fi
done
What this does:
--resampleWidth 800: Resamples the image so the width is at most 800 pixels, preserving aspect ratio. If the image is already ≤800px wide, it stays unchanged.--setProperty formatOptions best: Sets PNG compression to the highest (lossless) level. Combined with resampling, this typically reduces file size by 60-80%.- Original files are backed up to
images/papers/originals/before modification.
Other options (if you want even smaller files)
If you install additional tools via Homebrew:
# Install tools
brew install optipng pngquant
# Lossless PNG optimization (no quality loss, slower)
optipng -o7 images/papers/*.png
# Lossy PNG compression (slight quality loss, much smaller)
pngquant --quality=80-95 --force --ext .png images/papers/*.png
Adding new teaser images
When adding a new paper’s teaser image:
- Place the original image in
images/papers/as a PNG file - If the image is >500KB or >800px wide, run the
sipscompression above - Update
_pages/includes/pub.mdto reference the new image - Always include
loading='lazy'in the<img>tag for performance:<img loading='lazy' src='images/papers/new_paper.png' alt="description" width="100%">