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 might need to make changes to an article later on, for example, adding or modifying content in the Chinese version. It’s recommended to either edit the English version directly by hand, or just translate the modified parts.

Of course, you could also hand everything over to an LLM to generate a completely new translation. Alternatively, if you want to keep most of the content the same, you can first use Git’s diff feature to generate a log of the changes, and then use a similar prompt for the translation. However, this approach would require you to provide the new Chinese version, the old English version, and the file marking the differences, which is quite token-intensive and puts the model’s contextual understanding to the test.

git diff content/posts/xxx.md > temp.diff
输入:
- 一篇最新的中文文章、一个标注出变动的 diff 文件,以及一份较早版本的英文文章。

任务:
- 仅依据 diff 文件标注的差异,将中文文章的新改动融入英文文章更新。所有未变动内容需完全保留原英文表述。

规则:
1. 精准保留原有段落格式和结构。
2. 对变动部分进行流畅、地道的英文翻译。
3. 保持 Markdown 语法。仅翻译图片、链接、代码的说明与注释,除非特别要求,否则不应更改代码或 URL。
4. 保持原有语气与风格。根据语境匹配网络和口语化英文表达。

错误处理:
- 若缺少任一输入文件(中文文章、diff 文件或英文文章),回复:
  “错误:缺少必要输入文件。请提供中文文章、diff 文件和英文文章。”
- 若 diff 文件变动无法映射到英文文本,回复:
  “错误:无法将 diff 变更与英文文本对齐。请检查输入内容一致性。”

输出格式
- 英文文章输出:仅最终修订后的英文文章,确保可直接复制粘贴,无其他输出内容。

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