CLAUDE.md

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

Project Overview

This is a Jekyll-based academic/professional portfolio site (aaronzoll.github.io) using the Minimal Mistakes remote theme. It showcases research, teaching materials, and interactive math visualizations built with Desmos.

Commands

# Local development server with live reload
bundle exec jekyll serve

# Build for production
bundle exec jekyll build

# Install/update Ruby dependencies
bundle install

The site auto-deploys to GitHub Pages on push to main.

Architecture

Content Structure

Theming & Customization

The Minimal Mistakes theme is pulled as a remote theme — local files in _includes/, _layouts/, and _sass/ override the remote theme’s defaults.

Sass lives in _sass/minimal-mistakes/ and is compiled from assets/css/main.scss. Custom per-page styles are embedded in front matter or inline <style> blocks within the markdown.

Interactive Features

(function () { function preprocessLatex(el) { var h = el.innerHTML; var stash = [];

// Normalize LaTeX typographic double-quotes → Unicode
h = h.replace(/``/g, '“').replace(/''/g, '”');

// Strip block environments that have no web equivalent (figures, tikz)
h = h.replace(/\\begin\{figure\*?\}[\s\S]*?\\end\{figure\*?\}/g, '');
h = h.replace(/\\begin\{tikzpicture\}[\s\S]*?\\end\{tikzpicture\}/g, '');
h = h.replace(/\\begin\{algorithm\}[\s\S]*?\\end\{algorithm\}/g, '');

// Normalize \begin{env}{}{} / \begin{env}{} → \begin{env}
// (thmtools sometimes adds extra {} optional arguments)
h = h.replace(/\\begin\{(\w+)\}(\{\}){1,2}/g, '\\begin{$1}');

function save(s)    { var i = stash.length; stash.push(s); return '\x00' + i + '\x00'; }
function restoreAll(s) {
  // Iteratively restore in case stashed blocks contain other stash markers
  var prev;
  do {
    prev = s;
    s = s.replace(/\x00(\d+)\x00/g, function (_, i) { return stash[+i]; });
  } while (s !== prev);
  return s;
}

// 1. Stash and wrap standalone LaTeX display environments in \[...\]
var displayEnvs = ['align', 'alignat', 'equation', 'gather', 'multline', 'flalign', 'split'];
displayEnvs.forEach(function (e) {
  [e, e + '*'].forEach(function (env) {
    var esc = env.replace('*', '\\*');
    h = h.replace(
      new RegExp('\\\\begin\\{' + esc + '\\}([\\s\\S]*?)\\\\end\\{' + esc + '\\}', 'g'),
      function (m) { return save('\\[' + m + '\\]'); }
    );
  });
});

// 2. Stash existing \[...\] and $$...$$ display math
h = h.replace(/\\\[([\s\S]*?)\\\]/g,  function (m) { return save(m); });
h = h.replace(/\$\$([\s\S]*?)\$\$/g, function (m) { return save(m); });

// 3. Convert theorem environments to HTML, then stash
var envs = {
  theorem:     ['Theorem',     false],
  definition:  ['Definition',  false],
  proposition: ['Proposition', false],
  lemma:       ['Lemma',       false],
  corollary:   ['Corollary',   false],
  remark:      ['Remark',      false],
  example:     ['Example',     false],
  problem:     ['Problem',     false],
  algo:        ['Algorithm',   false],
  assumption:  ['Assumption',  false],
  proof:       ['Proof',       true ],
};
function inlineFormat(s) {
  s = s.replace(/\\textbf\{([^}]*)\}/g,    '<strong>$1</strong>');
  s = s.replace(/\\textit\{([^}]*)\}/g,    '<em>$1</em>');
  s = s.replace(/\\emph\{([^}]*)\}/g,      '<em>$1</em>');
  s = s.replace(/\\texttt\{([^}]*)\}/g,    '<code>$1</code>');
  s = s.replace(/\\underline\{([^}]*)\}/g, '<u>$1</u>');
  return s;
}
Object.keys(envs).forEach(function (name) {
  var label = envs[name][0], isProof = envs[name][1];
  h = h.replace(
    new RegExp('\\\\begin\\{' + name + '\\}(\\[([^\\]]*)\\])?([\\s\\S]*?)\\\\end\\{' + name + '\\}', 'g'),
    function (_, _br, opt, body) {
      body = inlineFormat(body);
      var html;
      if (isProof) {
        var cleaned = body
          .replace(/\\qed\b/g, '')
          .replace(/\\hfill\s*\$\\square\$\s*/g, '');
        html = '<div class="math-proof"><span class="math-env-title">Proof.</span> ' +
               cleaned +
               '<div class="proof-end">$\\square$</div></div>';
      } else {
        var t = opt ? label + ' (' + opt + ')' : label;
        html = '<div class="math-env math-env-' + name + '">' +
               '<span class="math-env-title">' + t + '.</span> ' +
               body + '</div>';
      }
      return save(html);
    }
  );
});

// 4. Stash section headings
h = h.replace(/\\section\*?\{([^}]*)\}/g,       function (_, t) { return save('<h2>' + t + '</h2>'); });
h = h.replace(/\\subsection\*?\{([^}]*)\}/g,    function (_, t) { return save('<h3>' + t + '</h3>'); });
h = h.replace(/\\subsubsection\*?\{([^}]*)\}/g, function (_, t) { return save('<h4>' + t + '</h4>'); });

// 5. Stash list environments
h = h.replace(/\\begin\{itemize\}([\s\S]*?)\\end\{itemize\}/g, function (_, c) {
  var items = c.split(/\\item/).slice(1).map(function (s) { return '<li>' + s.trim() + '</li>'; });
  return save('<ul>' + items.join('') + '</ul>');
});
h = h.replace(/\\begin\{enumerate\}([\s\S]*?)\\end\{enumerate\}/g, function (_, c) {
  var items = c.split(/\\item/).slice(1).map(function (s) { return '<li>' + s.trim() + '</li>'; });
  return save('<ol>' + items.join('') + '</ol>');
});

// 6. Inline text formatting (simple, non-nested arguments)
h = h.replace(/\\textbf\{([^}]*)\}/g,    '<strong>$1</strong>');
h = h.replace(/\\textit\{([^}]*)\}/g,    '<em>$1</em>');
h = h.replace(/\\emph\{([^}]*)\}/g,      '<em>$1</em>');
h = h.replace(/\\texttt\{([^}]*)\}/g,    '<code>$1</code>');
h = h.replace(/\\underline\{([^}]*)\}/g, '<u>$1</u>');
h = h.replace(/\\medskip\b/g,  '<div style="margin:0.6rem 0"></div>');
h = h.replace(/\\bigskip\b/g,  '<div style="margin:1.2rem 0"></div>');
h = h.replace(/\\smallskip\b/g,'<div style="margin:0.3rem 0"></div>');
h = h.replace(/\\noindent\b/g, '');
h = h.replace(/\\newline\b|\\\\(?!\[)/g, '<br>');

// 7. Strip \label, resolve \ref / \eqref as placeholders
h = h.replace(/\\label\{[^}]*\}/g, '');
h = h.replace(/\\eqref\{([^}]*)\}/g, '(?)');
h = h.replace(/\\[Cc]ref\{[^}]*\}/g, '?');
h = h.replace(/\\ref\{[^}]*\}/g, '?');

// 8. Paragraph wrapping: split on blank lines
var chunks = h.split(/\n{2,}/);
h = chunks.map(function (chunk) {
  chunk = chunk.trim();
  if (!chunk) return '';
  // Chunk that is purely a stash marker — restore as-is (block element)
  if (/^\x00\d+\x00$/.test(chunk)) return chunk;
  return '<p>' + chunk + '</p>';
}).filter(Boolean).join('\n');

el.innerHTML = restoreAll(h);   }

window._preprocessLatex = preprocessLatex; })();

// ── MathJax 3 configuration ────────────────────────────────────────────────── window.MathJax = { tex: { inlineMath: [[’$’, ‘$’], [’\(‘, ‘\)’]], displayMath: [[’\(', '\)’], [’\[’, ‘\]’]], tags: ‘ams’, macros: { // ── Trace / matrix ops ────────────────────────────────────────────── tr: ‘\mathrm{Tr}’, trace: ‘\mathrm{Tr}’, vect: ‘\mathbf{vec}’, bvec: [’{\mathbf{#1}}’, 1], matrx: [’\begin{bmatrix}#1\end{bmatrix}’, 1], diag: ‘\operatorname{diag}’, Diag: ‘\operatorname{Diag}’, rank: ‘\operatorname{rank}’, sign: ‘\operatorname{sign}’, // ── Calligraphic / script ──────────────────────────────────────────── cI: ‘\mathcal{I}’, cX: ‘\mathcal{X}’, cB: ‘\mathcal{B}’, cE: ‘\mathcal{E}’, cA: ‘\mathcal{A}’, cU: ‘\mathcal{U}’, cS: ‘\mathcal{S}’, Lcal: ‘\mathcal{L}’, Fscr: ‘\mathscr{F}’, // ── Blackboard bold ────────────────────────────────────────────────── F: ‘\mathbb{F}’, C: ‘\mathbb{C}’, R: ‘\mathbb{R}’, N: ‘\mathbb{N}’, NN: ‘\mathbb{N}’, ZZ: ‘\mathbb{Z}’, Q: ‘\mathbb{Q}’, EE: ‘\mathbb{E}’, Expect: ‘\mathbb{E}’, // ── Linear algebra / analysis operators ────────────────────────────── Dim: ‘\operatorname{dim}’, spann: ‘\operatorname{span}’, im: ‘\operatorname{Im}’, gph: ‘\operatorname{gph}’, supp: ‘\operatorname{supp}’, lip: ‘\operatorname{lip}’, var: ‘\operatorname{var}’, Var: ‘\operatorname{Var}’, op: ‘\mathrm{op}’, dist: ‘{\mathbf{dist}}’, proj: ‘\operatorname{proj}’, prox: ‘\operatorname{prox}’, St: ‘\text{subject to}’, // ── Delimiters / paired macros ─────────────────────────────────────── norm: [’\left\|#1\right\|’, 1], opnorm: [’\left\|#1\right\|_{\mathrm{op}}’, 1], abs: [’\left|#1\right|’, 1], inner: [’\left\langle#1,\,#2\right\rangle’, 2], Prob: [’\mathbb{P}\!\left(#1\right)’, 1], Expec: [’\mathbb{E}\!\left(#1\right)’, 1], dom: [’\operatorname{dom}(#1)’, 1], // ── Convex analysis ────────────────────────────────────────────────── epi: ‘\operatorname{epi}’, hypo: ‘\operatorname{hypo}’, interior: ‘\operatorname{int}’, bdry: ‘\operatorname{bdy}’, relint: ‘\operatorname{ri}’, argmin: ‘\operatorname{argmin}’, argmax: ‘\operatorname{argmax}’, mini: ‘\operatorname{minimize}’, ls: ‘\operatorname{limsup}’, // ── Misc ───────────────────────────────────────────────────────────── bcdot: ‘\ \mathbf{\cdot}\ ‘, eps: ‘\varepsilon’, Holder: ‘\text{Hölder}’, }, }, options: { skipHtmlTags: [‘script’, ‘noscript’, ‘style’, ‘textarea’, ‘pre’, ‘code’], }, startup: { ready() { function doPreprocess() { document.querySelectorAll(‘.latex-body’).forEach(function (el) { window._preprocessLatex(el); }); MathJax.startup.defaultReady(); } if (document.readyState === ‘loading’) { document.addEventListener(‘DOMContentLoaded’, doPreprocess); } else { doPreprocess(); } }, }, }; </script> ` in their front matter header or body.

Page Layouts

Most content pages use the splash layout with a hero header block (overlay color + image from picsum.photos). Research and teaching pages contain embedded HTML/CSS for custom grid layouts and slide presentations.

Key Conventions