This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Static personal website hosted on GitHub Pages at sebastianelsner.de. No build step, no framework, no package manager — plain HTML + a single CSS file, deployed directly from the master branch.
All pages use the engineering notebook aesthetic defined in css/notebook.css:
- Type: JetBrains Mono for structural / CV / metadata; EB Garamond italic for the music section disruption and for blog post body (long-form readability).
- Palette: warm paper (
--paper), ink, amber accent, oxblood reserved for the music section. Full dark-mode variant viaprefers-color-scheme: dark. - Fonts: served from
fonts.bunny.net(GDPR-compliant Google Fonts mirror). - Disruption rule: the music section is the only place that breaks from mono. Any new "fun" or personal section should follow the same pattern (paper-deep background, serif italic headline, oxblood accent).
-
Duplicate
blog/hello-world.htmland rename to a slug (e.g.blog/my-post.html). -
Update the head — change these and leave the rest alone:
<title><meta name="description">(target 110–160 chars)<meta property="og:title">(target 50–60 chars)<meta property="og:description"><meta property="og:url">og:type=article,og:site_name,twitter:card, the Bunny font links, the favicon links, and the Umami snippet are already correct from the duplicate — don't touch.
-
Update the body:
<h1>and.post-metadate.- For posts with a magazine-style subtitle, drop a
<p class="dek">subtitle</p>between the<h1>and.post-meta(italic EB Garamond — seeai-and-my-taxes.html). - Content lives inside
<div class="body">…</div>. Available tags:<p>,<h2>(serif italic oxblood),<h3>(small mono uppercase),<code>,<pre>,<ul>,<a>,<strong>,<em>,<sup>, plus<p class="tldr"><strong>TL;DR</strong> …</p>for the lede.
-
Add to
blog/index.htmlat the top of the writing list (newest first; the listing keeps every post):<a class="post" href="my-post.html"> <div class="when">Month DD, YYYY</div> <div class="body"> <h3>Post Title</h3> <p>One-line teaser.</p> </div> <div class="arrow" aria-hidden="true">→</div> </a>
-
Add the same teaser at the top of
<section class="writing">in the rootindex.html, and remove the oldest one so the home shows the latest 3 only. -
Generate the per-post OG card and point the post at it:
bin/og-card "Post Title" my-post "Month DD, YYYY"
That writes
assets/img/og-my-post.png(1200×630). Then update the post's head:<meta property="og:image" content="https://sebastianelsner.de/assets/img/og-my-post.png" /> <meta property="og:image:alt" content="Post Title — Sebastian Elsner, Month DD, YYYY" />
The script needs
inkscapeonPATHand nothing else. -
Verify locally before pushing — open the new post in a browser, check the dek/body styling and the OG card render at
/assets/img/og-my-post.png.
-
Site-level pages (root
index.html,blog/index.html) useassets/img/og.png— the brand card (name, manifesto, pillars). -
Each blog post has its own
assets/img/og-<slug>.pnggenerated bybin/og-card. Title centred, auto-wrapped up to 3 lines (32 chars/line). -
All cards render at 2× (2400×1260) so platform downscalers (LinkedIn, Slack, etc.) keep the mono text crisp after their JPEG re-encoding. The
og:image:width/og:image:heightmeta on every page reflects this. -
Brand card source lives at
bin/og-brand.svg. To regenerate after editing:inkscape bin/og-brand.svg --export-type=png \ --export-filename=assets/img/og.png \ --export-width=2400 --export-height=1260 -
Per-post template lives inside
bin/og-card(Python heredoc) — edit there if the design needs to change for all posts at once.
- Root pages link
css/notebook.cssandassets/img/favicon.ico. Blog pages use../css/notebook.cssand../assets/img/favicon.ico. - Every page must include the Bunny font preconnect + stylesheet link (JetBrains Mono + EB Garamond).
- Every page must include the Umami snippet just before
</head>. - Decorative glyphs (
##,¶,→,✓,_) carryaria-hidden="true". - Section headings use
<h2 class="name">inside<div class="sec-h">. Don't downgrade to<span>— heading hierarchy matters.
Every page includes:
<!-- Umami analytics -->
<script defer src="https://cloud.umami.is/script.js" data-website-id="73702148-36e0-4a0b-889e-6e1c29e062c0"></script>No templating layer, so this snippet must be present on every new HTML page. Duplicating an existing post carries it over automatically; pages created from scratch must add it manually.