https://github.com/asmuelle/asmuelle.github.io
Personal landing page — selected projects, live at asmuelle.github.io
https://github.com/asmuelle/asmuelle.github.io
Last synced: about 18 hours ago
JSON representation
Personal landing page — selected projects, live at asmuelle.github.io
- Host: GitHub
- URL: https://github.com/asmuelle/asmuelle.github.io
- Owner: asmuelle
- Created: 2026-06-17T22:18:10.000Z (20 days ago)
- Default Branch: main
- Last Pushed: 2026-06-30T07:37:51.000Z (7 days ago)
- Last Synced: 2026-06-30T09:23:59.090Z (7 days ago)
- Language: HTML
- Homepage: https://asmuelle.github.io/
- Size: 292 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# asmuelle.github.io
My personal landing page — selected work plus a live grid of recent projects,
served at **https://asmuelle.github.io/** in 10 languages.
📊 **[Repository status board → STATUS.md](./STATUS.md)** — live CI/check, commit,
and open-issue badges for every public repository.
## Generated, not hand-edited
The HTML pages are **built** from a single translation source, so do not edit
`index.html` (or the `de/`, `fr/`, … pages) by hand — your changes will be
overwritten on the next build.
- `scripts/i18n.mjs` — **single source of truth** for all copy, in 10 languages
(English, German, French, Spanish, Portuguese, Norwegian, Swedish, Danish,
Russian, Simplified Chinese). The build fails loudly if any language is missing
a key.
- `scripts/build-site.mjs` — generator. Emits one fully-translated, statically
rendered page per language (`index.html` = English at the root, `de/index.html`,
`fr/index.html`, …) plus `sitemap.xml`, `robots.txt`, `llms.txt` and `.nojekyll`.
Build:
```bash
node scripts/build-site.mjs
```
Why statically rendered per language: search engines index one language per URL,
and most AI/answer-engine crawlers (GPTBot, PerplexityBot, ClaudeBot …) don't run
JavaScript — so the localized content has to be in the served HTML, not swapped in
by JS. Each page carries `hreflang` alternates, a self-referencing canonical,
localized ``/meta/OpenGraph, and structured data.
## SEO / GEO
- **`hreflang`** — every page links all 10 locales + `x-default` (English root).
- **`sitemap.xml`** — all 10 URLs with reciprocal `hreflang` alternates.
- **`robots.txt`** — explicitly allows AI/answer-engine crawlers (being cited is
the goal) and points to the sitemap.
- **`llms.txt`** — plain-markdown profile/projects summary for AI engines.
- **JSON-LD** — `ProfilePage` + `Person` (with `knowsLanguage`, `sameAs`,
`email`) + `SoftwareApplication`/`SoftwareSourceCode` per flagship project +
`FAQPage`.
- **`sitemap-index.xml`** — a root-domain **sitemap index** that aggregates this
site's own `sitemap.xml` with every project Pages site's sitemap
(`asmuelle.github.io//sitemap.xml`). `robots.txt` points crawlers here, so
one entry discovers the whole portfolio. A sitemap index served from the host
root may reference URLs anywhere on the host, which is what makes per-repo
project sitemaps discoverable from a single place.
- **Language selector** — a styled `` that navigates to the localized URL
(real navigation, not client-side text swapping), with a `` link list.
## Other files
- `repos.json` — curated data for the *Also on GitHub* grid. Generated, not
hand-edited (see below).
- `og.png` / `og.svg` — 1200×630 social-share card referenced by the OpenGraph
and Twitter `summary_large_image` meta tags. Edit `og.svg`, then re-render
(`inkscape og.svg --export-type=png --export-filename=og.png -w 1200 -h 630`).
- `scripts/build-repos.sh` + `scripts/repos-filter.jq` — regenerate `repos.json`
from the GitHub API (non-forks, with a description, not already featured,
newest 6 by push date).
- `pages-projects.json` — source of truth for the sitemap index: the project Pages
sites whose `sitemap.xml` should be aggregated. Generated, not hand-edited.
- `scripts/build-sitemap-index.mjs` — renders `sitemap-index.xml` from
`pages-projects.json` (offline/deterministic; also called by `build-site.mjs`).
- `STATUS.md` — central repository status board (live CI/check, commit-freshness,
and open-issue badges for every public repo, with live links for Pages sites).
Generated, not hand-edited.
- `scripts/build-status.mjs` — regenerates `STATUS.md` from the GitHub API
(badges are dynamic, so only the repo list needs rebuilding). Requires `gh`
authenticated.
- `scripts/build-pages-projects.sh` — refreshes `pages-projects.json` from the
GitHub API: every owner repo with Pages enabled whose site actually **serves a
`sitemap.xml`** (probed live, so the index never points at a 404). Additive — a
listed project is kept even if a probe fails mid-rollout. Requires `gh`
authenticated.
- `.github/workflows/refresh-repos.yml` — runs the repos build **and** the
pages-projects/sitemap-index refresh daily (and on demand) with the
authenticated `GITHUB_TOKEN`, committing `repos.json`, `pages-projects.json`, and
`sitemap-index.xml` when they change. This keeps the grid static (no
unauthenticated rate limits) and the sitemap index current as projects ship.
## Grid data flow
The *Also on GitHub* grid loads at runtime in three tiers, degrading gracefully
(and localized via strings injected into each page at build time):
1. **`repos.json`** — fast, static, Action-generated. Preferred.
2. **Live GitHub API** — fallback if `repos.json` is missing/empty.
3. **A plain "browse on GitHub" link** — fallback if the API fails.
## Changing content
- **Copy / translations** → edit `scripts/i18n.mjs`, then `node scripts/build-site.mjs`.
- **Featured projects, services, FAQ structure** → edit the data arrays near the
top of `scripts/build-site.mjs`, then rebuild. Keep featured repo names in the
`FEATURED` arrays (in `build-site.mjs` and `scripts/build-repos.sh`) so they
stay out of the live grid.
- **Grid data** → `bash scripts/build-repos.sh` (requires `gh` authenticated).