Skip to content

jakethehoffer/website

Repository files navigation

website

Single-page resume for Jake Hoffman — the "engineering log" v2. Plain HTML, CSS, and a touch of vanilla JS. No framework, no build step.

Live at https://jakethehoffer.github.io/website/

Serve locally

python -m http.server 8000

Open http://localhost:8000/. You can also just double-click index.html — it works file:// too.

Adding or editing projects

Project content (cards on the site + entries on the resume) lives in projects.yml. To add or edit a project, change that one file and run:

python scripts/build-site.py

This calls three generators in order:

  • scripts/generate-cards.py — rewrites the <div class="projects"> block of index.html from projects.yml.
  • scripts/build-resume.py — builds resume-source.docx from scratch out of two tracked text files: resume-static.yml (contact header, summary, education, experience) + projects.yml (the PERSONAL PROJECTS section, by resume_priority + cap). No binary template; the docx is fully reproducible from text.
  • scripts/refresh-meta.py — refreshes last-commit timestamps for projects with auto_meta: true and stamps the footer last_deployed.

After running build-site.py, regenerate the PDF:

"C:/Program Files/LibreOffice/program/soffice.exe" --headless --convert-to pdf --outdir . resume-source.docx
mv resume-source.pdf resume.pdf

Commit index.html, the YAML you changed, and resume.pdf together. resume-source.docx is gitignored — it's a derived artifact, not a source.

Editing the resume

  • Projects on the resume: edit projects.yml (resume: block + resume_priority). See "Resume curation" below.
  • Everything else (contact line, summary, education, experience): edit resume-static.yml. It's plain, diffable text; the formatting (Garamond, margins, bullet/date layout) lives in build-resume.py.

projects.yml schema

Each entry:

field description
key short id; matches data-meta="<key>.last_commit" on the page
name displayed name in the card's <h3>
status active, shipped, or archived (controls the pill colour)
url external link; null = name renders without an <a> wrapper
private true → name renders as a private pill, not a (404-ing) link
case_study optional on-page anchor (e.g. "#case-study") for a [ read case study ↓ ] CTA
resume_priority int; higher = more important (drives resume curation, below)
meta_key data-meta sentinel key (usually <key>.last_commit)
auto_meta truerefresh-meta.py auto-updates the timestamp
hardcoded_date fallback string when auto_meta: false (e.g. "mar 2024")
what 1-2 sentence lede (HTML allowed for entities)
body 80-120 word description (HTML allowed)
metrics terse stats line (HTML entities pre-encoded)
chips tech-stack chips line
sample optional {label, html} for a code-block example
media optional {src, alt, width, height} for an image
cta optional {label, url} for an external CTA button
resume optional {role, bullets} for the resume; null/omit to skip

Project order in the rendered page matches order in projects.yml.

Resume curation (one-page guarantee)

The website shows every project. The resume shows only the top RESUME_MAX_PROJECTS (in scripts/build-resume.py, currently 4) of the projects that have a resume: block, ranked by resume_priority (highest first) and displayed in projects.yml order.

This means adding a project never forces manual cuts to EXPERIENCE/EDUCATION to keep the resume on one page — a new project simply competes for the capped slots. To feature a new project on the resume, give it a resume: block and a resume_priority higher than whichever project it should displace. (Because the docx is now built from scratch from text, the old PARAGRAPHS_TO_DROP trim-list — ~75 lines of page-fit hacks — is gone entirely.)

Automated weekly refresh

A GitHub Action at .github/workflows/refresh-meta.yml runs refresh-meta.py every Monday at 12:00 UTC (and on manual gh workflow run). It commits any changes back to main automatically.

The action reads META_REFRESH_TOKEN (a fine-grained PAT) from secrets. To set it up:

  1. Create a fine-grained PAT at https://github.com/settings/personal-access-tokens/new with Repository access → All repositories and Repository permissions → Metadata: Read. "All repositories" is the right scope so new projects are picked up automatically.
  2. Add it to the website repo at https://github.com/jakethehoffer/website/settings/secrets/actions as META_REFRESH_TOKEN.

Without the secret the workflow stays inert — the default GITHUB_TOKEN can only read the current repo, so every project with auto_meta: true logs [skip].

The resume.pdf pipeline

resume-source.docx is a derived artifact (gitignored). It's built from scratch by scripts/build-resume.py out of resume-static.yml + projects.yml, then LibreOffice converts it to resume.pdf. The full sequence is documented above in "Adding or editing projects". The committed resume.pdf is the only public-facing binary; the docx can always be regenerated from the tracked text sources.

Deploy

Drop the repo contents on any static host. GitHub Pages: push the repo, then in Settings → Pages, source = main branch / root.

Files

  • projects.yml — single source of truth for featured projects (site + resume).
  • resume-static.yml — tracked source for the resume's static sections (contact, summary, education, experience).
  • index.html — semantic single-page markup; projects block generated from projects.yml.
  • styles.css — all-mono design system, dark default + parchment light.
  • script.js — boot animation, mobile nav, theme toggle, IntersectionObserver reveal.
  • scripts/build-site.py — orchestrator (runs the three generators).
  • scripts/generate-cards.py — renders the projects block of index.html.
  • scripts/build-resume.py — builds resume-source.docx from scratch out of resume-static.yml + projects.yml.
  • scripts/refresh-meta.py — refreshes last-commit timestamps.
  • resume.pdf — downloadable PDF (the committed published artifact).
  • docs/superpowers/ — design specs and implementation plans.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors