Static site for vincentlarkin.com. Plain HTML/CSS/JS, deployed via GitHub Pages workflow in .github/workflows/deploy.yml.
| File | Purpose |
|---|---|
index.html |
Home. Renders both the legacy "classic" layout (used by theme-dark and theme-retro) and the rich vin-home-main layout (used by theme-vin). The legacy block is hidden in the VIN theme via CSS, the VIN block is hidden in the others. |
about.html |
Single contact card. |
news.html |
Curated articles (links into articles/) plus a bookshelf placeholder. |
gallery.html |
Monthly Gallery grouped by year (data lives in js/site.js) plus a paintings section that just links out to archive.vincentlarkin.com. |
changelog.html |
Live GitHub commit feed for this repo. |
header.html / footer.html |
Shared partials, fetched at runtime by js/site.js. Cache-busted with ?v=... (see PARTIAL_VERSION). |
| Path | Purpose |
|---|---|
css/styles.css |
Global layout, base typography, header/nav/footer skeleton, lightbox, holiday monitor, custom dropdown styles. |
css/theme-vin.css |
"Life of a VIN" theme (default). Gothic luxury look with the dark background and ornate cards. |
css/theme-dark.css |
Minimal dark theme overrides on top of the global default. |
css/theme-retro.css |
Retro IBM / NCSA Mosaic theme + fake browser chrome (chrome is injected by js/site.js). |
js/site.js |
App glue: SPA-style navigation, theme/language wiring, holiday monitor, monthly image renderer, GitHub commit fetcher, lightbox. |
js/i18n.js |
Translation system (English / Português / 日本語). All strings are embedded in embeddedTranslations; no JSON fetch. To add a new string, add a key with { en, pt, ja } values. To add a new language, append it to supportedLangs, give every translation key a value for that lang, add an entry to LANG_LABELS/LANG_FLAGS/LANG_LOCALES in js/site.js, and add an <li class="cs-option"> to the lang dropdown in header.html. |
images/site-emblem.png |
Brand mark used in the header. |
images/favicons/ |
Favicon set + site.webmanifest. |
images/flags/ |
us.png, pt.svg for the language switcher. |
images/themes/life-of-a-vin/background.webp |
Background art for theme-vin. |
images/profile.jpg |
Portrait shown on the About page bio block. Replace freely; if missing, the bio falls back to a "VL" monogram via the onerror handler. |
images/mês/ |
Monthly featured photos (originals). Folder name is Portuguese for "month" (note the ê). Filenames are referenced from monthlyImages in js/site.js. |
images/mês/thumbs/ |
~480px-wide WebP thumbnails used by the gallery grid. Pre-generated; see Adding a new monthly image. |
images/mês/thumbs-md/ |
~1024px-wide WebP thumbnails used by the home page "Image of the Month" card. |
images/articles/ |
Images embedded in articles/*.html. |
articles/ |
Long-form article HTML. Each one is self-contained and uses the same shared header/footer/CSS. |
robots.txt, sitemap.xml |
SEO. |
.github/workflows/deploy.yml |
GitHub Actions deploy pipeline. |
theme-vin ("Life of a VIN") is the default and is set in three places:
- Each HTML file:
<body class="theme-vin">. - The inline boot script in
index.htmlfalls back totheme-vin. getStoredTheme()injs/site.jsreturnstheme-vinif nothing valid is inlocalStorage.
Shared partials and JS bundles are loaded with ?v=PARTIAL_VERSION (see top of js/site.js). Bump that string when you change header.html, footer.html, js/site.js, or js/i18n.js so visitors don't get the stale cached copy.
The gallery and the home-page "Image of the Month" never load the original
file in the page — they load thumbnails out of thumbs/ and thumbs-md/ and
only fetch the original when the lightbox opens. So when you add a new
monthly image you also need to generate the two thumbnail variants.
-
Drop the original into
images/mês/(any of.jpg/.png/.webpworks, but WebP is preferred to keep the lightbox payload small). -
Generate the small + medium WebP thumbnails (requires
ffmpegon yourPATH):cd "images/mês" $base = "april-2026" # filename without extension $ext = "webp" # extension of the original ffmpeg -y -i "$base.$ext" -vf "scale='min(480,iw)':-1" -compression_level 6 -q:v 76 "thumbs/$base.webp" ffmpeg -y -i "$base.$ext" -vf "scale='min(1024,iw)':-1" -compression_level 6 -q:v 82 "thumbs-md/$base.webp"
Or, to (re)build thumbnails for every file in
images/mês/at once:Get-ChildItem images/mês -File | Where-Object { $_.Extension -in '.jpg','.jpeg','.png','.webp' } | ForEach-Object { $b = [IO.Path]::GetFileNameWithoutExtension($_.Name) ffmpeg -y -loglevel error -i $_.FullName -vf "scale='min(480,iw)':-1" -compression_level 6 -q:v 76 "images/mês/thumbs/$b.webp" ffmpeg -y -loglevel error -i $_.FullName -vf "scale='min(1024,iw)':-1" -compression_level 6 -q:v 82 "images/mês/thumbs-md/$b.webp" }
Targets: small ≈ 10–120 KB each, medium ≈ 70–650 KB each.
-
Add an entry at the top of the appropriate year array in
monthlyImagesinsidejs/site.js. Use the original filename —getMonthlyImagePaths()derives the thumb paths from it automatically. -
If the new image is the latest one, update the hard-coded
<img src>anddata-full-srcon#monthly-imageand#vin-monthly-imageinindex.htmlso the page renders the right image before JS runs. -
Bump
PARTIAL_VERSIONinjs/site.js(and?v=references in HTML) so visitors pick up the new data without a hard refresh.