跳至主要内容

部落格新增 RSS 圖示、文章列表修改

· 閱讀時間約 2 分鐘

新增 RSS 圖示

今天在部落格網站的招牌上新增了 RSS 圖示。

以前曾經想過加在 Menu,但是總覺得有點突兀、不好看,而且長度太長的話,手機上看 Menu 會變成兩行,畫面很怪。

也想過加在 Footer,不過我 Footer 的年份是用 JS 自動產生的(XD),這樣就要改 JS 或是改結構,但最主要還是視覺上怪怪的,可能要全部重新設計過 Footer 才適合放吧。

另外一個點是,我的首頁目前是顯示 「10 篇全文」,這樣要拉到很下面才找得到 RSS,太不友善了。

固定位置 SVG

最後選擇的做法是,先找一個 RSS 的 SVG ,固定放在 Header 右下角的位置。

直接內嵌 SVG 有一個好處,可以透過 CSS 自動調整圖示的大小。

SVG 圖示

<svg width="18" height="18" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-label="RSS 訂閱">
<rect width="24" height="24" rx="4" fill="#E8730A"/>
<circle cx="6.5" cy="17.5" r="2.5" fill="white"/>
<path d="M4 11.5C8.14 11.5 11.5 14.86 11.5 19" stroke="white" stroke-width="2.2" stroke-linecap="round" fill="none"/>
<path d="M4 6C11.18 6 17 11.82 17 19" stroke="white" stroke-width="2.2" stroke-linecap="round" fill="none"/>
</svg>

CSS

.header-rss {
position: absolute;
bottom: 10px;
right: 10px;
line-height: 0;
}

.header-rss svg {
width: clamp(18px, 3vw, 20px);
height: clamp(18px, 3vw, 20px);
}

文章列表

文章列表的部分,最開始是改成年份做區隔,但我發現我發的文章還挺多的,有分跟沒分差不多。

最後受到 Shuyu Pixelart 部落格的排版啟發,決定改成年+月來分類。

截圖

2026-03-02-screenshot.png

Dual-25:基因演算法策略

· 閱讀時間約 2 分鐘

Dual 25 是 Wiwi 在 睡前想到的紙牌對戰遊戲。(好玩!)

遊戲介紹

好想贏電腦

我(跟 LLM 互動)寫了一個固定策略,嘗試去贏過這個 MCTS 電腦。

接著再測試了一下對戰,以下是模擬結果:

  • 對戰場次:10000 場
    • ✅ 獲勝:5902 (59.0%)
    • 🤝 平手:1217 (12.2%)
    • ❌ 戰敗:2881 (28.8%)

(這樣應該還算不錯吧?)

試試看


訓練:基因演算法(GA)

  • 每種牌型定義 3 個權重參數:

    • 基礎參數base):該牌型的基礎分數
    • 牌型參數v):點數的權重,決定大牌還是小牌更優先
    • 危險參數danger):生命值越低時的傾向調整 = (25 - 當前生命值) / 25,範圍是 0~1
  • 每張牌會根據以下公式計算分數,分數最高的牌就會被選出:

    • attack = atk_base + v × atk_v + danger × atk_danger
    • counter = ctr_base + v × ctr_v + danger × ctr_danger
    • heal = heal_base + v × heal_v + danger × heal_danger
  • 訓練參數設定:

    • 族群大小:150 個個體
    • 演化世代:1000 代
    • 評估局數:每個體每世代評估 800 局
    • 評分機制:勝利 = 1.0 分,平手 = 0.5 分,失敗 = 0 分
    • 訓練對手:採用「隨機出牌」策略,這樣跑比較快(應該也比較不會 Overfitting?),不然用 MCTS 會訓練太久

額外補強

我最後再額外再加上「斬殺(lethal)」的概念。

  • 如果「反擊」或「攻擊」的數值高於對手的血量,則優先選擇斬殺(反擊優先)。
  • 如果有多張牌能斬殺,優先選擇點數小的牌做斬殺。

browser-sync 重複 reload 的解法

· 閱讀時間約 1 分鐘

上次在 更新網站產生器 的時候,有提到預覽功能 browser-sync 變得緩慢的問題。

今天才發現變慢的主因不是 build 產生太多檔案,而是因為偵測到太多檔案變動而不穩定。

一開始我改成偵測到檔案變動之後就去 build,然後產生一個 .reload 的檔案,裡面放 timestamp,這樣 browser-sync 只要去偵測這個檔案就可以了。

但是我也有一些檔案是不需要 build 的阿,這樣又要把路徑區分開來寫在 browser-sync,有點麻煩。

最後決定還是讓 browser-sync 偵測整個 public 資料夾,再加上兩個參數就解決了:

  • --reload-debounce 300:等檔案變動安靜下來再 reload。
  • --reload-delay 100:多等一點時間再刷新,避免被連續事件打爆。

2026/02/25 微更新

還是限制一下範圍比較好,像是這樣:

--files "public/assets/**/*.css"
--files "public/assets/**/*.js"
--files "public/*.html"
--files "content/**/*"

筆記

更新:部落格網站產生器

· 閱讀時間約 3 分鐘

前幾天在調整部落格時,有幾個痛點一直放著沒動,想說乾脆趁這個機會改一改。


痛點一

在生成器出現之前,我編輯的檔案跟最後部署的檔案是同一份,所以編輯時都是用 browser-sync 套件來預覽,只要按下儲存,網頁就會自動更新。

但是在生成器出現之後,如果我想要預覽新文章,就只能選這兩種方法:

  1. 每次想要預覽就只要重新 build 整個網站。
  2. 暫時在 index.htmlpreview.html 寫新文章,等編輯到滿意之後再放到真正的文章檔案,然後再重新 build 一次。

其實使用方法二也沒有多不方便,就是有點繞路而已。

解法

  • 新增 watch.php,監聽 content/articlestemplates 目錄變動,自動觸發 build。
  • 接著再整合 browser-sync,只要有變動,就同步到瀏覽器上。

痛點二

生成器在執行 build 的時候,會把所有文章都重新生成一次,久了會導致 browser-sync 變得緩慢,而且還「沒有刪除功能」,需要自己檢查有沒有殘留的頁面。

解法

這個老實說應該要分開做,正常來說應該是:

  1. build 是正式環境要用的,應該刪除整個資料夾,然後全部重新建構一次,這樣最安全。
  2. dev 是當下預覽用的,第一次啟動要全部 build 一遍,接下來則是根據有變動的檔案去 build 就好。

但我為求簡單,把它整合到一起了,而且 build 的時間基本上只有 0.1 秒,體感上幾乎感受不到。

  • 新增 Smart Write 機制,僅在檔案內容變動時才寫入,避免不必要的 I/O。
  • 新增 cleanStaleFiles(),自動清理多餘的分頁資料夾與文章資料夾(透過 slug 比對)。
  • 新增 summary(),建置完成後顯示更新的檔案列表。

這樣的話,每次 build 雖然會掃過所有文章,但如果只有修改內文,實際上只會生成:

  1. 首頁(或分頁)的文章內容
  2. 文章檔案(含資料夾)
  3. search.json
  4. rss.xml

痛點三

RSS 的 lastBuildDate 欄位每次 build 都會改成最後建置時間,但其實 RSS 內容完全沒變的時候是不需要上版的。

解法

  • RSS 的 lastBuildDate 改為最新文章發布日期,避免每次 build 的時候都變動。

新的發文流程

  • 點兩下 new-article.bat,建立新文章模板,並且自動填入今天日期。
  • 點兩下 auto-sync.bat,自動打開 browser-syncwatch.php,編輯儲存的時候會同步顯示到瀏覽器上。
  • (Optional)保險一點,自己再 build 一次。
  • 最後直接 commit + push 就行了。

檔案傳送工具

· 閱讀時間約 2 分鐘

昨天晚上臨時有個「電腦→電腦」傳大檔案的需求,大概是 80 GB 左右,因為不是在區域網路,所以平常用的 LocalSend 派不上用場(後來發現可以搭配 Tailscale 來傳),透過雲端服務的話,檔案會太大不好上傳,而且也滿沒效率的。

後來找到 Croc 跟 FilePizza 這兩種做法,我最後是選擇穩定好用的 Croc。

一開始我是用他們公用的 Relay 伺服器傳,但馬上就發現網路速度吃不滿,跑起來有點慢,看了文件之後發現可以自己架 Relay 伺服器,於是我就把我家 Router 的 NAT 轉址打開,直接用我的電腦來當 Relay 伺服器,這樣就可以把網路全部吃滿了。

這裡要吐槽自己一下,既然有 Public IP + NAT,那架 FTP Server 或用 LocalSend 指向 IP 其實就可以用了嘛~

這邊提一下,如果沒有辦法搞到 Public IP 或 NAT 轉址的話,也是有其他的做法的,像是可以把 Relay 伺服器架在 VPS 上面(但要注意流量限制),或者更好的選擇......用 Tailscale 啊!

Tailscale 也太好用了吧!(久仰大名,但這其實是我第一次用,以前都沒機會用到 XD)

總之,結論如下:

  • 如果你是要自己傳給自己,內網 LocalSend,外網搭配 Tailscale 就很夠用了。
  • 如果你臨時想要傳一些東西給別人,或者懶得裝軟體的話,就用 FilePizza。
  • 如果你想要穩定傳大檔案,又剛好有終端機可以用的話,可以選 Croc,速度不夠的話再搭配 Tailscale 架 Relay 伺服器。

使用情境

工具網路環境裝置特點
LocalSend區域網路跨裝置圖形介面、簡單易用
FilePizza跨網路跨裝置打開網頁就能用
Croc跨網路電腦之間大檔案、斷點續傳、自架 Relay

筆記

備份所有 GitHub Repositories

· 閱讀時間約 1 分鐘

備份檔案

今天在做(大約)一年一度的備份,把一些資料和電腦檔案備份到行動硬碟裡。

其中也包含雲端服務的資料,像是「Google Drive」、「Google Photos」這類的,用 Google Takeout 就能直接下載成 ZIP 檔,相當方便。

GitHub

至於 GitHub 嘛,就得自己想辦法處理了。

老實說,我原本是覺得好像沒有什麼 Repo 是一定要備份的,尤其在這個「大 AI 時代」,一些偏筆記型的 Repo 好像也沒那麼重要了,我甚至還順手砍掉了好幾個。

而且就算 GitHub 真的哪天掛了、資料不見了,也會有很多人一起陪葬啊,就像前陣子的一些 AWS、Cloudflare 故障一樣,大家要死就一起死,好像就沒那麼痛了?(好糟糕的心態 XD)

不過,從今年開始就不一樣了。

現在的 Repo 還包括我的「部落格」跟現在這個「文檔 + 部落格」,這些是我真的花了大量心血在上面的東西,就像日記本、照片一樣珍貴,所以還是要備份一下啦!

筆記

Cloudflare 即時聊天室

· 閱讀時間約 2 分鐘

聊天室

前陣子想說看可不可以用 Cloudflare Worker 來做個簡單的聊天室,因為我發現 Cloudflare Worker 雖然是 serverless,但是它的冷啟動時間超短,幾乎可以忽略不計。

總之,一般聊天室做法大概有三種:

  1. Polling
  2. Long Polling
  3. WebSocket

Polling

  • 資料儲存:使用 Cloudflare D1(基於 SQLite 的資料庫)
  • 讀取訊息:Worker 定期查詢 D1 獲取新訊息(每 4 秒查詢一次)
  • 傳送訊息:直接寫入 D1 資料庫
  • MOD 功能:可在 env 設定管理員密碼來刪除訊息
  • 安全限制:限制 API 速率、只能在指定網域使用等等

嗯...這個方法呢,稍微有點沒效率,尤其是一直去查詢資料庫的部分。

不過,以我這個小網站來說,用起來確實是沒問題的~

Long Polling

Long Polling 的原理是:Client 發送請求後,Worker 會等待一段時間(比如 30 秒),如果在這段時間內有新資料,就馬上回傳;如果時間到了還是沒資料,就直接回傳,然後再重新連接一次。

這個方法的問題是會一直占用 CPU,這樣非常浪費 Worker 的時間額度,所以感覺不太實際,就沒有去試了。

WebSocket

WebSocket 是一般比較正規的選擇。

  • 資料儲存:使用 Cloudflare Durable Objects 的 SQLite 方案
  • 連接管理:客戶端通過 WebSocket 建立持久連接到 Durable Object 上面
  • 傳送訊息:接收到訊息後直接 broadcast 給所有連接的人
  • 聊天歷史:通過 state.get()state.put() 等 Storage API 持久化到 SQLite

備註:如果是自己處理的話,就要架一個 WebSocket 伺服器;若想省事,就是用 Pusher 這類的第三方服務。

Bonus:交給別人來做

直接在網頁中崁入一個 Twitch 的聊天室就好了呀~(蛤?)

心得

因為我這次只是想試試看可行性,最後就只有做 Polling 而已,因為它足夠簡單,也已經夠用了。

再加上,我原本查 Durable Objects 好像是要付費的,不過現在好像有免費方案了!

如果未來真的有需要,可以直接用一些現成的、別人已經寫好的 Cloudflare Durable Objects 版本,這樣就能直接爽用啦~

Windows 環境測試 Safari 瀏覽器

· 閱讀時間約 1 分鐘

WebKit

前陣子在「DVD 彈跳動畫」這篇文章中,使用到 marquee 這個已經被棄用的 HTML 標籤,結果貼文發出後,才發現蘋果的 Safari 不支援這種作法,超級尷尬。

由於我手邊沒有蘋果的裝置可以拿來測試,於是在網路上搜尋了一下,發現在 Windows 的環境底下,可以透過 Playwright 內建的 Webkit 引擎來做測試。

有了這個方法之後,以後就很方便可以測試煩人的 WebKit(Safari 的引擎)啦~

筆記

FFmpeg 壓縮影片

· 閱讀時間約 1 分鐘

FFmpeg

上週在部落格上放了一些「復古遊戲的影片」。

我希望能夠兼顧支援度與畫質的同時,檔案也盡量不要太大。(Cloudflare Pages 檔案上限是 25 MB)

最後將影片都壓縮到 4 MB 左右,並維持 60 FPS 的流暢度,效果還算不錯。

我的小訣竅是:把編碼速度調到最慢,然後慢慢去調 CRF,直到「檔案大小」與「畫面品質」達到可接受的範圍就好囉~

筆記