Skip to content

About

My personal site: platform product work, full CV, imprint. Four static HTML pages, one stylesheet, self-hosted fonts, no build step.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Repository files navigation

carstenb.github.io

Personal website of Carsten Bokemeyer — hand-written static HTML, no build step, no generator, no runtime JavaScript.

Page File Language
Start index.html en
CV cv/index.html en
Imprint & privacy impressum/index.html de
Not found 404.html en

Layout

assets/site.css        All styling: tokens → shared shell → per-page blocks
assets/fonts/          Self-hosted woff2 + their OFL licences
assets/                Logo, portrait, company logos, favicons, OG image
design/og-card.html    Source template for assets/og-image.png — not deployed
site.webmanifest

Conventions

  • Asset paths are root-absolute (/assets/…). This is required, not cosmetic: GitHub Pages serves 404.html for any missing path while the address bar keeps the requested URL, so relative paths would break on the error page.
  • URLs always carry a trailing slash — /, /cv/, /impressum/. The same spelling is used in canonicals, Open Graph, the sitemap and internal links.
  • Fonts are self-hosted. Nothing is loaded from Google or any other third party. The privacy text in the imprint says so — if that ever changes, the text has to change with it.
  • Page-specific CSS is scoped by the body class: page-start, page-cv, page-imprint, page-404.
  • Copy comes from the design handoff and is authored — don't paraphrase it.

Regenerating the social preview

assets/og-image.png (1200×630) is exported from design/og-card.html:

./design/og-export.sh

It renders through headless Chrome so the real self-hosted webfonts are used. Never re-typeset the card in an image editor — edit the template and re-run the script, otherwise the image drifts from the site's typography.

The card's footer shows the address the site is served from, so it changes with the domain: edit the template, re-run the script, commit the new PNG.

Domain and hosting

The site is served from https://carsten-bokemeyer.de. carstenb.github.io redirects to it, as does www.

There is no CNAME file in this repo, and there must not be one. GitHub only writes one when a site publishes from a branch. This repo publishes from a custom Actions workflow, where any CNAME file is ignored; the domain lives in the Pages settings instead, alongside the source setting "GitHub Actions".

DNS at the registrar (dogado):

carsten-bokemeyer.de              A      185.199.108-111.153  (four records)
carsten-bokemeyer.de              AAAA   2606:50c0:8000-8003::153  (four records)
www                               CNAME  carstenb.github.io.
_github-pages-challenge-carstenb  TXT    domain verification, optional

One thing worth knowing if HTTPS ever gets stuck again: the certificate covers the apex and www together. While www had no DNS record at all, GitHub could not complete the challenge for that name, so no certificate was issued for either, and "Enforce HTTPS" stayed greyed out for five days with nothing in the interface explaining why. Check that both names resolve before looking anywhere else.

GitHub profile README

The profile at github.com/carstenb comes from the repo carstenb/carstenb, which is build output only. Don't edit it there; the next sync overwrites it.

npm run profile

prints the README. profile/build.js takes identity from the JSON-LD, and the claim, topics, Mandoria headline, companies and contact address from index.html. It also sets the claim as an SVG header in the site's fonts and colours. profile/README.template.md holds the structure and the copy that only exists for GitHub. The rule: facts, identity, positioning and reusable content come from the site; GitHub-specific wording stays in the template.

Extraction is strict. If a markup change leaves it without a claim, topic or company, the validate workflow fails on the PR. After a merge that touches any of its inputs, sync-profile-readme.yml builds the profile and mirrors it into carstenb/carstenb.

The sync needs the Actions secret PROFILE_REPO_TOKEN: a fine-grained token for carstenb/carstenb only, with Contents: Read and write. It expires. When it does, the sync fails and the profile stays as it was until a new token is stored.

Manual upkeep

Not covered by any automation:

  • The © 2026 in the footer of all four pages.
  • The imprint text (legal content).
  • Renewing PROFILE_REPO_TOKEN before it expires.

If the domain ever changes again, these move together. design/check.js asserts most of them, so it will fail loudly on anything missed:

index.html, cv/index.html, impressum/index.html   canonical, og:url, og:image
index.html                                        JSON-LD url, @id, image
sitemap.xml                                       both <loc> entries
robots.txt                                        the Sitemap: line
design/check.js                                   the ORIGIN constant
design/og-card.html                               footer line, then re-export

Outside the repo: the Pages custom domain setting, the DNS records above, and the Search Console property.

History

The previous Hugo site is preserved at the tag old-site-2021.

About

My personal site: platform product work, full CV, imprint. Four static HTML pages, one stylesheet, self-hosted fonts, no build step.

Topics

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages