Personal blog for 0xemperor.net. The posts are the original Mirror essays (2022–2024), recovered from Arweave — not the lossy Paragraph import.
Built with Hugo. No theme dependency; all layouts are local.
hugo server # http://localhost:1313content/posts/— one markdown file per essay (canonical text, from Mirror/Arweave)assets/img/<slug>/— every image, downloaded locally; nothing hotlinks Mirror/Paragraphstatic/img/tweets/— avatars and media for embedded tweetsdata/tweets.json— static snapshots of every embedded tweet (survive deletion)data/links.json— titles for bare-URL link cardslayouts/— templates: flat home list, post page, tweet/link-card shortcodes, an image render hook that adds<figure>/<figcaption>(alt text = caption)import/arweave/versions/— archived JSON of every version of every Mirror postimport/paragraph/— the Paragraph export converted to markdown, for comparison onlyimport/REPORT.md— Mirror-vs-Paragraph content diff report
Scripts are idempotent and cache everything (Arweave JSON, images, tweets):
source ~/.venv/bin/activate
python scripts/import_mirror.py # arweave -> content/posts/ (+ images)
python scripts/fetch_tweets.py # tweet snapshots -> data/tweets.json
python scripts/import_paragraph.py # paragraph feed -> import/ + REPORT.md
python scripts/import_substack.py <url> # a Substack post -> content/posts/
python scripts/gen_og.py # regenerate social cards in static/og/--offline skips network for import_mirror.py; --refresh re-fetches tweets.
hugo new posts/my-post.mdFront matter: math: true enables KaTeX ($$…$$ display, \(…\) inline).
Shortcodes: {{</* tweetcard id="123" */>}} (add the tweet to data/tweets.json
via scripts/fetch_tweets.py), {{</* linkcard url="https://…" */>}}.
Not wired up yet (intentionally). hugo --minify builds to public/.
Note: a running hugo server also writes to public/ with localhost URLs —
stop it (or build with -d <dir>) before producing a deployable build.