How I update

Hugo is a tool that converts Markdown files into static HTML pages. In theory, you just create or edit Markdown, then run hugo and it’s done. In practice, there are some tiny details worth sharing.

Github Actions

For convenience, my blog uses two repos: one stores Markdown and the Hugo theme and other files; the other stores the generated site files (i.e., Github Pages). The first repo has Github Actions that run the hugo command, build static pages, then push to the second repo.

The Action is triggered whenever commits are pushed to the main branch. Each run takes about a minute. With 3,000 Action minutes per month on Github, I’ll never run out.

Draft

Sometimes a post is half-written or I don’t want to publish it yet. In that case I set draft to true in the front matter, so hugo won’t build it. But if it’s in main, it still triggers the Action—even though nothing changes. So I made a draft branch to keep those posts. That way I can use Git like cloud sync and also avoid triggering the Action.

LLM post-processing

After I finish the draft, I’ll have AI read and check it—like spotting typos, checking fluency, and giving suggestions (which I mostly skim, or let models like GPT-4o say some nice words). If I haven’t written the summary, description, or even the title yet, I’ll ask it for options—though most of the time they’re not that useful.

I use GPT 4.1 for this step. Stronger models are fine too, but LLMs aren’t great at precisely controlling the word count of the generated text.

输入将会是完整的 markdown,是由简体中文创作的个人博客的一篇文章。

你需要首先查看是否存在错别字、错误的用词和用语,表述不清晰,不通顺的地方。清晰的指出在何处、有什么问题、如何修改。注意,这是一个个人博客,适当的口语化是可接受的,但不能冒犯。

然后,你需要结合你的知识和理解,仔细的阅读文章内容,给出一些内容上的建议和读后感。

最后,你需要结合内容和你的理解,给出几个 front 部分的 title,summary 和 description 的备选项,符合以下要求:

- title:这将是显示在文章列表中和文章顶部的“标题”,最好不超过 25 个汉字。
- summary:这将是显示在文章列表中,标题下方的文章“总结”或“副标题”,既补充说明标题,又代表文章内容,最好不超过 50 个汉字。
- description:这将显示在文章页面的标题下方第一段,是“摘要”,是开头和预告全文。最好不超过 80 个汉字。

以及,给出一个文件名,它将作为该文章的 URL,比如 xxx.md,将会成为 baseURL/posts/xxx

After the Chinese version is done, for a bit of internationalization, I also generate an English version. In Hugo, you just create a file with the same name xxx.en.md. The English draft is also written by an LLM. If the post is about color science, I’ll provide a glossary to help the AI with terms. Aside from a few similar terms (which we often don’t strictly distinguish anyway), larger models translate quite well. Good options include Gemini 2.5 Pro and DeepSeek R1-0528; the latter sometimes gives better translation quality, but it may alter format and paragraphs. After translating, I’ll read it once and make small edits if I have time.

Recentlt, A model named Horizon on OpenRouter also works very well for this task. Update: Horizon appears to be gpt-5-mini, while gpt-5 performs relatively well on both tasks.

Here’s the prompt I use. Supposedly, for reasoning models, a clear prompt is enough, you don’t need a super complicated one:

I found that OpenAI has a Prompt Optimizer. It’s kind of like ByteDance’s old Prompt Pilot. Here is a prompt tuned for GPT-5 but works fine with other models too.

输入内容为完整的 Markdown,内容为简体中文创作的个人博客文章。

你的任务是将内容翻译为英文,生成对应的英文版本。

要求:
1. 保持原有格式和段落完全不变。
2. 译文表达需自然、贴近日常习惯,避免生僻或不常用表达。
3. 保持 Markdown 语法,图片链接和代码部分只需翻译图片描述和注释。
4. 保持原文语气和风格,网络用语和俚语需准确对应。

在开始翻译前,生成一份 3-5 步的简要任务清单。
翻译完成后仅输出英文内容,便于直接复制粘贴,无需包含其他信息。

遇到专业术语时,以下是供你参考的词典:
- 亮度:Luminance
- 明度:Lightness
- 视明度:Brightness

Sometimes you need to update a post after it’s published. After adding or editing the Chinese version, how do you update it while keeping everything else unchanged, and still make the updates blend in naturally? A one-shot chat with an LLM usually won’t cut it. The best way is to lean on an agent, such as GitHub Copilot or Codex, with a tiny bit of guidance.

使用 `git diff` 检查我对文件 `ccontent\posts\badge-and-blog-workflow.md` 做的更改,依据以下规则,将修改同步到英文版的文章中 `content\posts\badge-and-blog-workflow.en.md`,只修改有改动的部分,保持其他部分不变,要求风格与原本接近。

翻译规则:

1. 保持格式和段落严格不变。
2. 注意用语和用词,不要出现生僻的单词,符合日常习惯。
3. 保持 markdown 语法,图片链接、代码部分只要翻译图片描述和注释。
4. 保持语气,使用的俚语和网络用语需要准确的翻译。

It will read the files, run commands to view the diffs, and accurately translate only the changed parts.

A Badge for visitor stats

Source

Found this little gadget while surfing: show visitor counts through a Badge, like on this site. Did some digging and found it’s just an image; each load increments a counter by 1.

The image comes from visitor-badge.laobi.icu, a free service. You only need an image URL.

The image link format is below. Replace page.id with a unique string. I’m using jacksblog now—just avoid collisions. Super convenient. To reset the count, just swap in a new string.

https://visitor-badge.laobi.icu/badge?page_id=page.id

Of course, this is just a fun toy. Every image load increments the counter. If you add it to the footer like I did, it shows on every page. This way, from visiting the homepage, to entering the article list, to opening a specific article, the counter might increase three times. Additionally, refreshing the page also adds to the count.

Add to the page

Next is adding the Badge to the page. I chose to place it below the footer text. Claude Code handled this part; here’s its own summary of the work.

Step 1: Config separation

Separate the visitor badge from the footer text and configure it in hugo.yaml:

Location: hugo.yaml

footer:
  text: "footer text here."
visitorsImage: "https://visitor-badge.laobi.icu/badge?page_id="
  • Add a new visitorsImage param to store the badge URL
  • Keep the footer text clean

Step 2: Theme extension

Modify the extend_footer.html of the PaperMod theme to display the badge:

Location: themes/PaperMod/layouts/partials/extend_footer.html

{{- if .Site.Params.visitorsImage -}}
<div style="text-align: center; margin-top: 10px; margin-bottom: 20px; width: 100%; display: flex; justify-content: center;">
    <img src="{{ .Site.Params.visitorsImage }}" alt="visitors" style="max-width: 120px; height: auto;" />
</div>
{{- end -}}
  • {{- if .Site.Params.visitorsImage -}}: Conditional display; only show when visitorsImage is set
  • {{ .Site.Params.visitorsImage }}: Read the param from hugo.yaml
  • {{- -}}: Trim extra whitespace
  • text-align: center: Center align text
  • width: 100%: Container takes full width
  • display: flex; justify-content: center: Flexbox to center horizontally
  • margin-top: 10px; margin-bottom: 20px: Space around the footer, leave some bottom padding
  • max-width: 120px: Limit badge max width to avoid oversized display
  • height: auto: Keep aspect ratio

Notes

  1. Theme updates: If you update PaperMod, you’ll need to reapply the extend_footer.html changes
  2. Third-party dependency: Relies on an external stats service; if it’s down, you’ll see a broken image
  3. Privacy: Visitor stats collect access data; make sure it aligns with your privacy policy