Blog 改版(個人品牌主站)Implementation Plan

Blog 改版(個人品牌主站)Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: 把 yazelin.github.io 從 Beautiful Jekyll 預設版型改成自寫版型的個人品牌主站——首頁 landing(定位句+作品牆+故事+精選文章+訂閱)、blog 退居 /blog,205 篇舊網址不斷。

Architecture: 移除 remote_theme,自寫 4 個 Jekyll layouts(default/page/post/首頁與 /blog 用頁面檔)+ 一份 CSS。email 收名單沿用 k-rider-api Worker(加 source: "blog")。全部工作在 rebrand branch,驗收過後一次 merge 上線(GitHub Pages 從 master 部署)。

Tech Stack: Jekyll(GitHub Pages 內建)、jekyll-paginate、jekyll-feed、jekyll-sitemap、giscus、Cloudflare Worker + D1(既有 k-rider-api)、Playwright(驗證)。

Global Constraints

File Structure

yazelin.github.io/
├── _config.yml                  # 改:移除 remote_theme、paginate_path、navbar 資料化
├── _layouts/
│   ├── default.html             # 新:骨架(head/nav/footer)
│   ├── page.html                # 新:一般頁(about/tags/404/workshop/portfolio)
│   ├── post.html                # 新:文章頁(giscus/相關文章/CTA/TOC)
│   └── home.html                # 新:/blog 列表(paginator+搜尋)
├── _includes/
│   ├── head-custom.html         # 留(JSON-LD)
│   ├── nav.html                 # 新
│   ├── footer.html              # 新(三件套+email/yt)
│   ├── signup-form.html         # 新(訂閱表單,可重複 include)
│   └── giscus.html              # 新
├── assets/css/site.css          # 新:全站樣式(design tokens)
├── assets/js/blog-search.js     # 新:/blog 客戶端搜尋
├── search.json                  # 新:搜尋索引(Liquid 產生)
├── index.html                   # 改:landing(hero/作品牆/故事/精選/CTA)
├── blog/index.html              # 新:文章列表(原首頁功能)
├── images/portfolio/*.webp      # 新:作品牆截圖
└── docs/superpowers/plans/...   # 本檔

k-rider/worker/src/signup.js     # 改:source 白名單加 'blog'

Task 1: k-rider-api Worker 接受 source “blog”

Files:

Interfaces:

Read /home/ct/k-rider/worker/src/signup.js 全文與 ls /home/ct/k-rider/tests/。若 tests 內有 signup 相關測試,加一個 case;若無,不新增測試框架(以 curl 驗證)。

// signup.js:28 原:
const source = ['result', 'about', 'home'].includes(body.source) ? body.source : null;
// 改:
const source = ['result', 'about', 'home', 'blog'].includes(body.source) ? body.source : null;
cd /home/ct/k-rider/worker && npx wrangler deploy
curl -s -X POST https://k-rider-api.yazelinj303.workers.dev/api/signup \
  -H 'content-type: application/json' -H 'Origin: https://yazelin.github.io' \
  -d '{"email":"plan-test-blog@example.com","company":"","source":"blog"}'

Expected: {"ok":true,...}。再用 admin 端點(Authorization: Bearer $ADMIN_TOKEN)確認該列 sourceblog(token 在 wrangler secret,查法:問 yazelin 或用 npx wrangler d1 execute k-rider-signups --remote --command "SELECT email,source FROM signups ORDER BY id DESC LIMIT 3")。驗完刪測試列:DELETE FROM signups WHERE email='plan-test-blog@example.com'

cd /home/ct/k-rider && git add worker/src/signup.js && git commit -m "feat(signup): accept source 'blog' for blog rebrand funnel

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"

Task 2: 移除主題、建立 default/page layouts 與 CSS(站能 build、一般頁能看)

Files:

Interfaces:

移除 remote_themeavatar/round-avatarnavbar-linksshare-links-activepost_searchexcerpt_length(Beautiful Jekyll 專屬鍵);保留 title/author/description/url/markdown/timezone/plugins/feed 設定/giscus 區塊/defaults/exclude。加:

paginate: 10
paginate_path: "/blog/page:num/"

navbar:
  - title: Blog
    url: /blog/
  - title: About
    url: /about/
  - title: Portfolio
    url: /portfolio/
  - title: Workshop
    url: /workshop/
  - title: Tags
    url: /tags/

(Projects 下拉選單捨棄——作品改由首頁作品牆呈現;此為刻意簡化。)

<!doctype html>
<html lang="zh-Hant">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Blog 改版(個人品牌主站)Implementation Plan — Yaze</title>
  <meta name="description" content="Software Developer from Taiwan">
  <link rel="canonical" href="https://yazelin.github.io/docs/superpowers/plans/2026-07-15-blog-rebrand.html">
  <meta property="og:title" content="Blog 改版(個人品牌主站)Implementation Plan">
  <meta property="og:description" content="Software Developer from Taiwan">
  <meta property="og:url" content="https://yazelin.github.io/docs/superpowers/plans/2026-07-15-blog-rebrand.html">
  <meta property="og:type" content="website">
  
  <link rel="icon" href="">
  <link rel="alternate" type="application/rss+xml" title="Yaze" href="https://yazelin.github.io/feed.xml">
  <link rel="stylesheet" href="/assets/css/site.css">
  <!-- 注入給搜尋引擎與 AI(AEO/GEO)的結構化資料。Beautiful Jekyll 的 head 會 include 本檔。 -->
<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "Yaze's Blog",
  "url": "https://yazelin.github.io/",
  "inLanguage": "zh-Hant",
  "author": {
    "@type": "Person",
    "name": "林亞澤 Yaze",
    "alternateName": "yazelin",
    "url": "https://yazelin.github.io/",
    "image": "",
    "jobTitle": "Software Developer",
    "description": "台灣的軟體開發者,從工業自動化系統整合轉做 AI 應用與互動網頁。",
    "sameAs": [
      "https://github.com/yazelin",
      "https://www.youtube.com/@yazelin"
    ]
  }
}
</script>

</head>
<body>
  <!-- _includes/nav.html -->
<header class="site-nav">
  <a class="brand" href="/">Yaze</a>
  <nav>
    
    <a href="/blog/">Blog</a>
    
    <a href="/about/">About</a>
    
    <a href="/portfolio/">Portfolio</a>
    
    <a href="/workshop/">Workshop</a>
    
    <a href="/tags/">Tags</a>
    
  </nav>
</header>

  <main><article class="page container">
  <h1>森之魔道具工坊</h1>
  <link rel="preconnect" href="https://fonts.googleapis.com" />

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" />

<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;600&amp;family=IM+Fell+English:ital@0;1&amp;family=Noto+Serif+TC:wght@400;500;600;700&amp;display=swap" rel="stylesheet" />

<style>
  /* ==========================================================
     森之魔道具工坊 · Scoped Styles
     僅作用於 .forest-workshop 內,不影響其他頁面
     ========================================================== */
  .forest-workshop {
    --forest-deep: #1e3328;
    --forest-mid: #2d4a3e;
    --forest-moss: #4a6b5a;
    --parchment: #f5efe0;
    --parchment-dark: #e8dcc0;
    --ink: #1a1a1a;
    --ink-soft: #4a4a4a;
    --gold: #c9a24d;
    --gold-soft: #d4b572;
    --mist: #6b8a99;
    --serif-en: "Cinzel", "IM Fell English", Georgia, serif;
    --serif-zh: "Noto Serif TC", "PingFang TC", "Source Han Serif TC", serif;
  }

  /* --- 序章 Prologue --- */
  .forest-workshop .prologue {
    margin: 2rem auto 3rem;
    padding: 3rem 2rem 2.5rem;
    background:
      radial-gradient(ellipse at top, rgba(201,162,77,0.12) 0%, transparent 60%),
      linear-gradient(135deg, var(--forest-deep) 0%, var(--forest-mid) 100%);
    color: var(--parchment);
    border-radius: 6px;
    text-align: center;
    box-shadow: 0 4px 20px rgba(0,0,0,0.25);
    position: relative;
    overflow: hidden;
  }
  .forest-workshop .prologue::before {
    content: "";
    position: absolute;
    top: 0; left: 50%;
    transform: translateX(-50%);
    width: 1px; height: 40px;
    background: linear-gradient(to bottom, transparent, var(--gold), transparent);
  }
  .forest-workshop .prologue-mark {
    font-family: var(--serif-en);
    font-size: 0.75rem;
    letter-spacing: 0.4em;
    color: var(--gold);
    text-transform: uppercase;
    margin-bottom: 1rem;
  }
  .forest-workshop .prologue-title {
    font-family: var(--serif-zh);
    font-size: 1.75rem;
    font-weight: 400;
    line-height: 1.6;
    margin: 0.5rem auto 1.2rem;
    max-width: 680px;
    color: var(--parchment);
  }
  .forest-workshop .prologue-lore {
    font-family: var(--serif-zh);
    font-size: 1rem;
    line-height: 1.9;
    max-width: 620px;
    margin: 0 auto;
    color: var(--parchment-dark);
    opacity: 0.92;
  }
  .forest-workshop .prologue-en {
    margin-top: 1.5rem;
    padding-top: 1.2rem;
    border-top: 1px solid rgba(201,162,77,0.3);
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.9rem;
    color: var(--gold-soft);
    letter-spacing: 0.05em;
  }

  /* --- 系別標籤 --- */
  .forest-workshop .school-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    margin: 2rem 0;
    font-family: var(--serif-zh);
    font-size: 0.85rem;
  }
  .forest-workshop .school-tag {
    padding: 0.3rem 0.85rem;
    background: var(--parchment);
    color: var(--forest-deep);
    border: 1px solid var(--parchment-dark);
    border-radius: 999px;
    font-weight: 500;
  }

  /* --- 魔道具卡片 --- */
  .forest-workshop .codex-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 1.5rem;
    margin: 2rem 0 3rem;
  }
  .forest-workshop .artifact {
    background: var(--parchment);
    border: 1px solid var(--parchment-dark);
    border-radius: 4px;
    padding: 1.5rem 1.4rem 1.3rem;
    position: relative;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    box-shadow: 0 1px 3px rgba(30,51,40,0.08);
  }
  .forest-workshop .artifact:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 18px rgba(30,51,40,0.15);
  }
  .forest-workshop .artifact-head {
    display: flex;
    align-items: flex-start;
    gap: 0.8rem;
    margin-bottom: 0.9rem;
  }
  .forest-workshop .artifact-icon {
    font-size: 2rem;
    line-height: 1;
    flex-shrink: 0;
    margin-top: 2px;
  }
  .forest-workshop .artifact-names {
    flex: 1;
    min-width: 0;
  }
  .forest-workshop .artifact-name-zh {
    font-family: var(--serif-zh);
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--forest-deep);
    line-height: 1.3;
    margin: 0;
  }
  .forest-workshop .artifact-name-en {
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.8rem;
    color: var(--ink-soft);
    letter-spacing: 0.03em;
    margin-top: 2px;
  }
  .forest-workshop .artifact-repo {
    font-family: Menlo, "Fira Code", Consolas, monospace;
    font-size: 0.72rem;
    color: var(--mist);
    margin-top: 1px;
  }
  .forest-workshop .artifact-school {
    position: absolute;
    top: 1rem;
    right: 1rem;
    font-family: var(--serif-zh);
    font-size: 0.7rem;
    color: var(--gold);
    letter-spacing: 0.08em;
    background: var(--forest-deep);
    padding: 0.2rem 0.55rem;
    border-radius: 2px;
  }
  .forest-workshop .artifact-lore {
    font-family: var(--serif-zh);
    font-size: 0.88rem;
    line-height: 1.75;
    color: var(--ink);
    margin: 0.8rem 0 1rem;
    padding-left: 0.8rem;
    border-left: 2px solid var(--gold-soft);
    font-style: italic;
  }
  .forest-workshop .artifact-effect {
    font-family: var(--serif-zh);
    font-size: 0.85rem;
    line-height: 1.7;
    color: var(--ink-soft);
    margin: 0.6rem 0 1.2rem;
  }
  .forest-workshop .artifact-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 1rem;
    padding-top: 0.9rem;
    border-top: 1px dashed var(--parchment-dark);
  }
  .forest-workshop .artifact-btn {
    font-family: var(--serif-en);
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 0.4rem 0.9rem;
    border-radius: 2px;
    text-decoration: none;
    transition: all 0.15s ease;
    border: 1px solid transparent;
  }
  .forest-workshop .artifact-btn.primary {
    background: var(--forest-deep);
    color: var(--gold-soft);
    border-color: var(--forest-deep);
  }
  .forest-workshop .artifact-btn.primary:hover {
    background: var(--forest-mid);
    color: var(--parchment);
    text-decoration: none;
  }
  .forest-workshop .artifact-btn.secondary {
    background: transparent;
    color: var(--forest-deep);
    border-color: var(--forest-moss);
  }
  .forest-workshop .artifact-btn.secondary:hover {
    background: var(--forest-moss);
    color: var(--parchment);
    text-decoration: none;
  }

  /* --- 系別區分 --- */
  .forest-workshop .school-divider {
    font-family: var(--serif-zh);
    font-size: 0.95rem;
    color: var(--forest-mid);
    margin: 2.5rem 0 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--parchment-dark);
    display: flex;
    align-items: baseline;
    gap: 0.8rem;
  }
  .forest-workshop .school-divider-en {
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.8rem;
    color: var(--mist);
    letter-spacing: 0.05em;
  }

  /* --- 後記 --- */
  .forest-workshop .epilogue {
    margin: 3rem 0 1rem;
    padding: 2rem;
    background: var(--parchment);
    border: 1px solid var(--parchment-dark);
    border-left: 3px solid var(--gold);
    border-radius: 2px;
    font-family: var(--serif-zh);
    font-size: 0.9rem;
    line-height: 1.85;
    color: var(--ink-soft);
  }
  .forest-workshop .epilogue strong {
    color: var(--forest-deep);
  }

  @media (max-width: 640px) {
    .forest-workshop .prologue-title { font-size: 1.4rem; }
    .forest-workshop .prologue { padding: 2rem 1.2rem 1.8rem; }
    .forest-workshop .codex-grid { grid-template-columns: 1fr; }
  }
</style>

<div class="forest-workshop">

<section class="prologue">
  <div class="prologue-mark">— Codex of Artifacts —</div>
  <h2 class="prologue-title">森之大魔導師打造的魔道具,<br />自由取閱,自由傳承。</h2>
  <p class="prologue-lore">
    此地名為「森之工坊」,是我與契約精靈 Mori 共同打造魔道具的所在。<br />
    每件魔道具皆為多年修練與失敗累積而成,開放給願意與 AI 同行的冒險者自由領取。<br />
    願你能從中取得一件相合的器物,帶回你自己的森林。
  </p>
  <div class="prologue-en">
    Artifacts crafted in the quiet of the woods, by the Archmage and the spirit Mori.<br />
    Take what speaks to you. Carry it into your own forest.
  </div>
</section>

<!-- ============================================================ -->
<!-- 召喚系 · Summoning                                            -->
<!-- ============================================================ -->
<h3 class="school-divider">
  召喚系 <span class="school-divider-en">· Summoning Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">召喚系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🐱</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">時之貓苑</h4>
      <div class="artifact-name-en">Chronocat</div>
      <div class="artifact-repo">yazelin/catime</div>
    </div>
  </div>
  <div class="artifact-lore">
    每至整點,森林深處便浮現一隻新貓。有 103 種藝術流派的皮毛,各自攜帶一段小故事。
  </div>
  <div class="artifact-effect">
    GitHub Actions 每小時呼叫 Gemini 生成 AI 貓圖,發至 Telegram 頻道與 Gallery 歸檔。已累積數千隻。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://yazelin.github.io/catime/" target="_blank">Gallery</a>
    <a class="artifact-btn secondary" href="https://t.me/catime_yaze" target="_blank">Telegram</a>
    <a class="artifact-btn secondary" href="https://github.com/yazelin/catime" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 幻術系 · Illusion                                             -->
<!-- ============================================================ -->
<h3 class="school-divider">
  幻術系 <span class="school-divider-en">· Illusion Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">幻術系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎰</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">心情占卜儀</h4>
      <div class="artifact-name-en">Moodscopia</div>
      <div class="artifact-repo">yazelin/emoji-slot-machine</div>
    </div>
  </div>
  <div class="artifact-lore">
    取冒險者一張自拍,映入九宮魔陣,瞬間化為九格誇張表情。貼入 FB 結界後自動循環,手指一碰便停在隨機一格。
  </div>
  <div class="artifact-effect">
    Cloudflare Worker + Vertex AI。自拍 → 3×3 emoji 臉 → 可嵌入 FB 的拉霸影片。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://yazelin.github.io/emoji-slot-machine/" target="_blank">試用</a>
    <a class="artifact-btn secondary" href="https://github.com/yazelin/emoji-slot-machine" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 創造系 · Creation                                             -->
<!-- ============================================================ -->
<h3 class="school-divider">
  創造系 <span class="school-divider-en">· Creation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎨</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">繪影魔陣</h4>
      <div class="artifact-name-en">Portrait Circle</div>
      <div class="artifact-repo">yazelin/nanobanana-pro</div>
    </div>
  </div>
  <div class="artifact-lore">
    能自動在多個創造之神之間換手,繪製出最切合意念的圖像。若一神拒絕,轉請下一神。
  </div>
  <div class="artifact-effect">
    AI 圖像生成 Agent Skill,支援自動模型 fallback。可接入 Claude Code 或其他 agent 生態。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/nanobanana-pro" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🖼️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">繪風傳承書</h4>
      <div class="artifact-name-en">Painted Tome</div>
      <div class="artifact-repo">yazelin/gemini-web</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓神靈(Gemini)在此作畫,支援繁體符文、不留神印(自動去浮水印)。
  </div>
  <div class="artifact-effect">
    Gemini AI 圖片生成 CLI + HTTP API。繁中原生、浮水印自動處理。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/gemini-web" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📜</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">咒文起稿匣</h4>
      <div class="artifact-name-en">Spell Composer</div>
      <div class="artifact-repo">yazelin/PromptFill</div>
    </div>
  </div>
  <div class="artifact-lore">
    為繪影魔陣準備咒文草稿的輔助匣。結構化、省去散亂冥想。
  </div>
  <div class="artifact-effect">
    結構化 AI 繪圖 prompt 產生器,適配 Nano Banana Pro 系列。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/PromptFill" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 煉金系 · Transmutation                                        -->
<!-- ============================================================ -->
<h3 class="school-divider">
  煉金系 <span class="school-divider-en">· Transmutation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">煉金系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📄</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">卷軸化術</h4>
      <div class="artifact-name-en">Scribe's Hand</div>
      <div class="artifact-repo">yazelin/MD2DOC-Evolution</div>
    </div>
  </div>
  <div class="artifact-lore">
    將凡人墨跡(Markdown)煉成正式卷軸(Word)。格式可客製化,符合任何行會規範。
  </div>
  <div class="artifact-effect">
    Markdown → Word,支援企業自訂樣式、表格、圖片、目錄。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/MD2DOC-Evolution" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">煉金系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📽️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">簡報祭壇</h4>
      <div class="artifact-name-en">Lectern of Light</div>
      <div class="artifact-repo">yazelin/MD2PPT-Evolution</div>
    </div>
  </div>
  <div class="artifact-lore">
    將墨跡化為幻燈(PPT),可現場投影展示。支援線上宣講模式。
  </div>
  <div class="artifact-effect">
    Markdown → PPT,含線上簡報與投影模式,支援程式碼語法高亮。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/MD2PPT-Evolution" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 次元系 · Dimensional                                          -->
<!-- ============================================================ -->
<h3 class="school-divider">
  次元系 <span class="school-divider-en">· Dimensional Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">次元系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🗄️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">藏影閣</h4>
      <div class="artifact-name-en">Shadow Vault</div>
      <div class="artifact-repo">yazelin/image-bed</div>
    </div>
  </div>
  <div class="artifact-lore">
    個人圖像的次元書架,不佔本空間,存入神殿(GitHub Releases)異界,永不損壞。
  </div>
  <div class="artifact-effect">
    個人圖床,圖片存放在 GitHub Releases,不佔 repo 空間。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/image-bed" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">次元系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🔗</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">傳送門刻印</h4>
      <div class="artifact-name-en">Portal Rune</div>
      <div class="artifact-repo">yazelin/shorturl-worker</div>
    </div>
  </div>
  <div class="artifact-lore">
    將漫長的咒文路徑封印為短刻印,單手即可傳送冒險者。
  </div>
  <div class="artifact-effect">
    Cloudflare Workers + KV 縮網址服務,PromptFill 專用短網址。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/shorturl-worker" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 通靈系 · Binding                                              -->
<!-- ============================================================ -->
<h3 class="school-divider">
  通靈系 <span class="school-divider-en">· Binding Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">通靈系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🖨️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">印刻術</h4>
      <div class="artifact-name-en">Inkseal</div>
      <div class="artifact-repo">yazelin/printer-mcp</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓精靈能直接指揮凡人印刷術(CUPS),將任何訊息化為實體。
  </div>
  <div class="artifact-effect">
    MCP server,透過 CUPS 控制印表機。可接 Claude / Cursor 等 agent。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/printer-mcp" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">通靈系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🏢</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">帳本監聽術</h4>
      <div class="artifact-name-en">Ledger Whisper</div>
      <div class="artifact-repo">yazelin/erpnext-mcp</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓精靈與商會帳本(ERPNext)直接對話,問帳、記帳不必經過凡人之手。
  </div>
  <div class="artifact-effect">
    MCP server for ERPNext REST API,讓 AI 能直接查詢、記錄商業數據。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/erpnext-mcp" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 聲術系 · Incantation                                          -->
<!-- ============================================================ -->
<h3 class="school-divider">
  聲術系 <span class="school-divider-en">· Incantation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">聲術系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎙️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">詠唱辨識器</h4>
      <div class="artifact-name-en">Voice Scribe</div>
      <div class="artifact-repo">yazelin/asr-ime-fcitx</div>
    </div>
  </div>
  <div class="artifact-lore">
    將咒術師的口語即時記下為文字,嵌入 fcitx 輸入法,隨呼隨用。
  </div>
  <div class="artifact-effect">
    ASR 語音輸入法,整合 fcitx framework。支援中英雙語。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/asr-ime-fcitx" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 後記 Epilogue                                                 -->
<!-- ============================================================ -->
<div class="epilogue">
  <strong>關於工坊 · About this Workshop</strong><br />
  此處列出的魔道具多為我與 Mori 共同打造的作品,部分為教學範例、部分為日常使用工具。
  若其中任何一件對你有用,歡迎 fork、改造、延伸。<br />
  新的魔道具會持續加入此處 — 這是一間還在生長的工坊。<br /><br />
  <em style="color: var(--mist); font-family: var(--serif-en);">
    Each artifact here was forged in collaboration with Mori, my contracted spirit.
    Some are teaching examples, others are daily tools. All are open. Take what you need.
  </em>
</div>

</div>

</article>
</main>
  <!-- _includes/footer.html -->
<footer class="site-footer">
  <div class="footer-links">
    <a href="https://github.com/yazelin">GitHub</a>
    <a href="https://www.facebook.com/yaze.lin.gm">Facebook</a>
    <a href="https://buymeacoffee.com/yazelin">Buy Me a Coffee</a>
    <a href="https://www.youtube.com/@yazelin">YouTube</a>
    <a href="mailto:yaze.lin.j303@gmail.com">Email</a>
  </div>
  <p class="footer-note">© 2026 林亞澤 Yaze — <a href="/feed.xml">RSS</a></p>
</footer>

</body>
</html>
<!-- _includes/nav.html -->
<header class="site-nav">
  <a class="brand" href="/">Yaze</a>
  <nav>
    
    <a href="/blog/">Blog</a>
    
    <a href="/about/">About</a>
    
    <a href="/portfolio/">Portfolio</a>
    
    <a href="/workshop/">Workshop</a>
    
    <a href="/tags/">Tags</a>
    
  </nav>
</header>
<!-- _includes/footer.html -->
<footer class="site-footer">
  <div class="footer-links">
    <a href="https://github.com/yazelin">GitHub</a>
    <a href="https://www.facebook.com/yazelinj303">Facebook</a>
    <a href="https://buymeacoffee.com/yazelin">Buy Me a Coffee</a>
    <a href="https://www.youtube.com/@yazelin">YouTube</a>
    <a href="mailto:yaze.lin.j303@gmail.com">Email</a>
  </div>
  <p class="footer-note">© 2026 林亞澤 Yaze — <a href="/feed.xml">RSS</a></p>
</footer>

(FB/BMC 實際網址以 yazelin 現有三件套為準——實作時 grep 任一公開專案 README footer 取正確 URL,不要用上面猜的。)

<!-- _layouts/page.html -->
---
layout: default
---
<article class="page container">
  <h1>Blog 改版(個人品牌主站)Implementation Plan</h1>
  <article class="page container">
  <h1>森之魔道具工坊</h1>
  <link rel="preconnect" href="https://fonts.googleapis.com" />

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" />

<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;600&amp;family=IM+Fell+English:ital@0;1&amp;family=Noto+Serif+TC:wght@400;500;600;700&amp;display=swap" rel="stylesheet" />

<style>
  /* ==========================================================
     森之魔道具工坊 · Scoped Styles
     僅作用於 .forest-workshop 內,不影響其他頁面
     ========================================================== */
  .forest-workshop {
    --forest-deep: #1e3328;
    --forest-mid: #2d4a3e;
    --forest-moss: #4a6b5a;
    --parchment: #f5efe0;
    --parchment-dark: #e8dcc0;
    --ink: #1a1a1a;
    --ink-soft: #4a4a4a;
    --gold: #c9a24d;
    --gold-soft: #d4b572;
    --mist: #6b8a99;
    --serif-en: "Cinzel", "IM Fell English", Georgia, serif;
    --serif-zh: "Noto Serif TC", "PingFang TC", "Source Han Serif TC", serif;
  }

  /* --- 序章 Prologue --- */
  .forest-workshop .prologue {
    margin: 2rem auto 3rem;
    padding: 3rem 2rem 2.5rem;
    background:
      radial-gradient(ellipse at top, rgba(201,162,77,0.12) 0%, transparent 60%),
      linear-gradient(135deg, var(--forest-deep) 0%, var(--forest-mid) 100%);
    color: var(--parchment);
    border-radius: 6px;
    text-align: center;
    box-shadow: 0 4px 20px rgba(0,0,0,0.25);
    position: relative;
    overflow: hidden;
  }
  .forest-workshop .prologue::before {
    content: "";
    position: absolute;
    top: 0; left: 50%;
    transform: translateX(-50%);
    width: 1px; height: 40px;
    background: linear-gradient(to bottom, transparent, var(--gold), transparent);
  }
  .forest-workshop .prologue-mark {
    font-family: var(--serif-en);
    font-size: 0.75rem;
    letter-spacing: 0.4em;
    color: var(--gold);
    text-transform: uppercase;
    margin-bottom: 1rem;
  }
  .forest-workshop .prologue-title {
    font-family: var(--serif-zh);
    font-size: 1.75rem;
    font-weight: 400;
    line-height: 1.6;
    margin: 0.5rem auto 1.2rem;
    max-width: 680px;
    color: var(--parchment);
  }
  .forest-workshop .prologue-lore {
    font-family: var(--serif-zh);
    font-size: 1rem;
    line-height: 1.9;
    max-width: 620px;
    margin: 0 auto;
    color: var(--parchment-dark);
    opacity: 0.92;
  }
  .forest-workshop .prologue-en {
    margin-top: 1.5rem;
    padding-top: 1.2rem;
    border-top: 1px solid rgba(201,162,77,0.3);
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.9rem;
    color: var(--gold-soft);
    letter-spacing: 0.05em;
  }

  /* --- 系別標籤 --- */
  .forest-workshop .school-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    margin: 2rem 0;
    font-family: var(--serif-zh);
    font-size: 0.85rem;
  }
  .forest-workshop .school-tag {
    padding: 0.3rem 0.85rem;
    background: var(--parchment);
    color: var(--forest-deep);
    border: 1px solid var(--parchment-dark);
    border-radius: 999px;
    font-weight: 500;
  }

  /* --- 魔道具卡片 --- */
  .forest-workshop .codex-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 1.5rem;
    margin: 2rem 0 3rem;
  }
  .forest-workshop .artifact {
    background: var(--parchment);
    border: 1px solid var(--parchment-dark);
    border-radius: 4px;
    padding: 1.5rem 1.4rem 1.3rem;
    position: relative;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    box-shadow: 0 1px 3px rgba(30,51,40,0.08);
  }
  .forest-workshop .artifact:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 18px rgba(30,51,40,0.15);
  }
  .forest-workshop .artifact-head {
    display: flex;
    align-items: flex-start;
    gap: 0.8rem;
    margin-bottom: 0.9rem;
  }
  .forest-workshop .artifact-icon {
    font-size: 2rem;
    line-height: 1;
    flex-shrink: 0;
    margin-top: 2px;
  }
  .forest-workshop .artifact-names {
    flex: 1;
    min-width: 0;
  }
  .forest-workshop .artifact-name-zh {
    font-family: var(--serif-zh);
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--forest-deep);
    line-height: 1.3;
    margin: 0;
  }
  .forest-workshop .artifact-name-en {
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.8rem;
    color: var(--ink-soft);
    letter-spacing: 0.03em;
    margin-top: 2px;
  }
  .forest-workshop .artifact-repo {
    font-family: Menlo, "Fira Code", Consolas, monospace;
    font-size: 0.72rem;
    color: var(--mist);
    margin-top: 1px;
  }
  .forest-workshop .artifact-school {
    position: absolute;
    top: 1rem;
    right: 1rem;
    font-family: var(--serif-zh);
    font-size: 0.7rem;
    color: var(--gold);
    letter-spacing: 0.08em;
    background: var(--forest-deep);
    padding: 0.2rem 0.55rem;
    border-radius: 2px;
  }
  .forest-workshop .artifact-lore {
    font-family: var(--serif-zh);
    font-size: 0.88rem;
    line-height: 1.75;
    color: var(--ink);
    margin: 0.8rem 0 1rem;
    padding-left: 0.8rem;
    border-left: 2px solid var(--gold-soft);
    font-style: italic;
  }
  .forest-workshop .artifact-effect {
    font-family: var(--serif-zh);
    font-size: 0.85rem;
    line-height: 1.7;
    color: var(--ink-soft);
    margin: 0.6rem 0 1.2rem;
  }
  .forest-workshop .artifact-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 1rem;
    padding-top: 0.9rem;
    border-top: 1px dashed var(--parchment-dark);
  }
  .forest-workshop .artifact-btn {
    font-family: var(--serif-en);
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 0.4rem 0.9rem;
    border-radius: 2px;
    text-decoration: none;
    transition: all 0.15s ease;
    border: 1px solid transparent;
  }
  .forest-workshop .artifact-btn.primary {
    background: var(--forest-deep);
    color: var(--gold-soft);
    border-color: var(--forest-deep);
  }
  .forest-workshop .artifact-btn.primary:hover {
    background: var(--forest-mid);
    color: var(--parchment);
    text-decoration: none;
  }
  .forest-workshop .artifact-btn.secondary {
    background: transparent;
    color: var(--forest-deep);
    border-color: var(--forest-moss);
  }
  .forest-workshop .artifact-btn.secondary:hover {
    background: var(--forest-moss);
    color: var(--parchment);
    text-decoration: none;
  }

  /* --- 系別區分 --- */
  .forest-workshop .school-divider {
    font-family: var(--serif-zh);
    font-size: 0.95rem;
    color: var(--forest-mid);
    margin: 2.5rem 0 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--parchment-dark);
    display: flex;
    align-items: baseline;
    gap: 0.8rem;
  }
  .forest-workshop .school-divider-en {
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.8rem;
    color: var(--mist);
    letter-spacing: 0.05em;
  }

  /* --- 後記 --- */
  .forest-workshop .epilogue {
    margin: 3rem 0 1rem;
    padding: 2rem;
    background: var(--parchment);
    border: 1px solid var(--parchment-dark);
    border-left: 3px solid var(--gold);
    border-radius: 2px;
    font-family: var(--serif-zh);
    font-size: 0.9rem;
    line-height: 1.85;
    color: var(--ink-soft);
  }
  .forest-workshop .epilogue strong {
    color: var(--forest-deep);
  }

  @media (max-width: 640px) {
    .forest-workshop .prologue-title { font-size: 1.4rem; }
    .forest-workshop .prologue { padding: 2rem 1.2rem 1.8rem; }
    .forest-workshop .codex-grid { grid-template-columns: 1fr; }
  }
</style>

<div class="forest-workshop">

<section class="prologue">
  <div class="prologue-mark">— Codex of Artifacts —</div>
  <h2 class="prologue-title">森之大魔導師打造的魔道具,<br />自由取閱,自由傳承。</h2>
  <p class="prologue-lore">
    此地名為「森之工坊」,是我與契約精靈 Mori 共同打造魔道具的所在。<br />
    每件魔道具皆為多年修練與失敗累積而成,開放給願意與 AI 同行的冒險者自由領取。<br />
    願你能從中取得一件相合的器物,帶回你自己的森林。
  </p>
  <div class="prologue-en">
    Artifacts crafted in the quiet of the woods, by the Archmage and the spirit Mori.<br />
    Take what speaks to you. Carry it into your own forest.
  </div>
</section>

<!-- ============================================================ -->
<!-- 召喚系 · Summoning                                            -->
<!-- ============================================================ -->
<h3 class="school-divider">
  召喚系 <span class="school-divider-en">· Summoning Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">召喚系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🐱</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">時之貓苑</h4>
      <div class="artifact-name-en">Chronocat</div>
      <div class="artifact-repo">yazelin/catime</div>
    </div>
  </div>
  <div class="artifact-lore">
    每至整點,森林深處便浮現一隻新貓。有 103 種藝術流派的皮毛,各自攜帶一段小故事。
  </div>
  <div class="artifact-effect">
    GitHub Actions 每小時呼叫 Gemini 生成 AI 貓圖,發至 Telegram 頻道與 Gallery 歸檔。已累積數千隻。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://yazelin.github.io/catime/" target="_blank">Gallery</a>
    <a class="artifact-btn secondary" href="https://t.me/catime_yaze" target="_blank">Telegram</a>
    <a class="artifact-btn secondary" href="https://github.com/yazelin/catime" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 幻術系 · Illusion                                             -->
<!-- ============================================================ -->
<h3 class="school-divider">
  幻術系 <span class="school-divider-en">· Illusion Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">幻術系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎰</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">心情占卜儀</h4>
      <div class="artifact-name-en">Moodscopia</div>
      <div class="artifact-repo">yazelin/emoji-slot-machine</div>
    </div>
  </div>
  <div class="artifact-lore">
    取冒險者一張自拍,映入九宮魔陣,瞬間化為九格誇張表情。貼入 FB 結界後自動循環,手指一碰便停在隨機一格。
  </div>
  <div class="artifact-effect">
    Cloudflare Worker + Vertex AI。自拍 → 3×3 emoji 臉 → 可嵌入 FB 的拉霸影片。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://yazelin.github.io/emoji-slot-machine/" target="_blank">試用</a>
    <a class="artifact-btn secondary" href="https://github.com/yazelin/emoji-slot-machine" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 創造系 · Creation                                             -->
<!-- ============================================================ -->
<h3 class="school-divider">
  創造系 <span class="school-divider-en">· Creation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎨</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">繪影魔陣</h4>
      <div class="artifact-name-en">Portrait Circle</div>
      <div class="artifact-repo">yazelin/nanobanana-pro</div>
    </div>
  </div>
  <div class="artifact-lore">
    能自動在多個創造之神之間換手,繪製出最切合意念的圖像。若一神拒絕,轉請下一神。
  </div>
  <div class="artifact-effect">
    AI 圖像生成 Agent Skill,支援自動模型 fallback。可接入 Claude Code 或其他 agent 生態。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/nanobanana-pro" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🖼️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">繪風傳承書</h4>
      <div class="artifact-name-en">Painted Tome</div>
      <div class="artifact-repo">yazelin/gemini-web</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓神靈(Gemini)在此作畫,支援繁體符文、不留神印(自動去浮水印)。
  </div>
  <div class="artifact-effect">
    Gemini AI 圖片生成 CLI + HTTP API。繁中原生、浮水印自動處理。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/gemini-web" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📜</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">咒文起稿匣</h4>
      <div class="artifact-name-en">Spell Composer</div>
      <div class="artifact-repo">yazelin/PromptFill</div>
    </div>
  </div>
  <div class="artifact-lore">
    為繪影魔陣準備咒文草稿的輔助匣。結構化、省去散亂冥想。
  </div>
  <div class="artifact-effect">
    結構化 AI 繪圖 prompt 產生器,適配 Nano Banana Pro 系列。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/PromptFill" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 煉金系 · Transmutation                                        -->
<!-- ============================================================ -->
<h3 class="school-divider">
  煉金系 <span class="school-divider-en">· Transmutation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">煉金系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📄</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">卷軸化術</h4>
      <div class="artifact-name-en">Scribe's Hand</div>
      <div class="artifact-repo">yazelin/MD2DOC-Evolution</div>
    </div>
  </div>
  <div class="artifact-lore">
    將凡人墨跡(Markdown)煉成正式卷軸(Word)。格式可客製化,符合任何行會規範。
  </div>
  <div class="artifact-effect">
    Markdown → Word,支援企業自訂樣式、表格、圖片、目錄。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/MD2DOC-Evolution" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">煉金系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📽️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">簡報祭壇</h4>
      <div class="artifact-name-en">Lectern of Light</div>
      <div class="artifact-repo">yazelin/MD2PPT-Evolution</div>
    </div>
  </div>
  <div class="artifact-lore">
    將墨跡化為幻燈(PPT),可現場投影展示。支援線上宣講模式。
  </div>
  <div class="artifact-effect">
    Markdown → PPT,含線上簡報與投影模式,支援程式碼語法高亮。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/MD2PPT-Evolution" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 次元系 · Dimensional                                          -->
<!-- ============================================================ -->
<h3 class="school-divider">
  次元系 <span class="school-divider-en">· Dimensional Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">次元系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🗄️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">藏影閣</h4>
      <div class="artifact-name-en">Shadow Vault</div>
      <div class="artifact-repo">yazelin/image-bed</div>
    </div>
  </div>
  <div class="artifact-lore">
    個人圖像的次元書架,不佔本空間,存入神殿(GitHub Releases)異界,永不損壞。
  </div>
  <div class="artifact-effect">
    個人圖床,圖片存放在 GitHub Releases,不佔 repo 空間。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/image-bed" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">次元系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🔗</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">傳送門刻印</h4>
      <div class="artifact-name-en">Portal Rune</div>
      <div class="artifact-repo">yazelin/shorturl-worker</div>
    </div>
  </div>
  <div class="artifact-lore">
    將漫長的咒文路徑封印為短刻印,單手即可傳送冒險者。
  </div>
  <div class="artifact-effect">
    Cloudflare Workers + KV 縮網址服務,PromptFill 專用短網址。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/shorturl-worker" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 通靈系 · Binding                                              -->
<!-- ============================================================ -->
<h3 class="school-divider">
  通靈系 <span class="school-divider-en">· Binding Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">通靈系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🖨️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">印刻術</h4>
      <div class="artifact-name-en">Inkseal</div>
      <div class="artifact-repo">yazelin/printer-mcp</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓精靈能直接指揮凡人印刷術(CUPS),將任何訊息化為實體。
  </div>
  <div class="artifact-effect">
    MCP server,透過 CUPS 控制印表機。可接 Claude / Cursor 等 agent。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/printer-mcp" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">通靈系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🏢</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">帳本監聽術</h4>
      <div class="artifact-name-en">Ledger Whisper</div>
      <div class="artifact-repo">yazelin/erpnext-mcp</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓精靈與商會帳本(ERPNext)直接對話,問帳、記帳不必經過凡人之手。
  </div>
  <div class="artifact-effect">
    MCP server for ERPNext REST API,讓 AI 能直接查詢、記錄商業數據。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/erpnext-mcp" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 聲術系 · Incantation                                          -->
<!-- ============================================================ -->
<h3 class="school-divider">
  聲術系 <span class="school-divider-en">· Incantation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">聲術系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎙️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">詠唱辨識器</h4>
      <div class="artifact-name-en">Voice Scribe</div>
      <div class="artifact-repo">yazelin/asr-ime-fcitx</div>
    </div>
  </div>
  <div class="artifact-lore">
    將咒術師的口語即時記下為文字,嵌入 fcitx 輸入法,隨呼隨用。
  </div>
  <div class="artifact-effect">
    ASR 語音輸入法,整合 fcitx framework。支援中英雙語。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/asr-ime-fcitx" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 後記 Epilogue                                                 -->
<!-- ============================================================ -->
<div class="epilogue">
  <strong>關於工坊 · About this Workshop</strong><br />
  此處列出的魔道具多為我與 Mori 共同打造的作品,部分為教學範例、部分為日常使用工具。
  若其中任何一件對你有用,歡迎 fork、改造、延伸。<br />
  新的魔道具會持續加入此處 — 這是一間還在生長的工坊。<br /><br />
  <em style="color: var(--mist); font-family: var(--serif-en);">
    Each artifact here was forged in collaboration with Mori, my contracted spirit.
    Some are teaching examples, others are daily tools. All are open. Take what you need.
  </em>
</div>

</div>

</article>

</article>

assets/css/site.css(完整檔;design tokens + 全站基礎 + 之後 task 會用到的 landing/blog/post 區塊都先放齊):

:root {
  --fg: #1c1917; --muted: #6b6560; --bg: #fdfcfa; --card: #ffffff;
  --border: #e8e5e1; --accent: #047857; --accent-weak: #ecfdf5;
  --maxw: 46rem; --maxw-wide: 68rem;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; background: var(--bg); color: var(--fg);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans TC", "Microsoft JhengHei", sans-serif;
  line-height: 1.75; font-size: 17px; letter-spacing: 0.01em;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
img { max-width: 100%; height: auto; }
h1, h2, h3 { line-height: 1.3; letter-spacing: 0.02em; }
code { background: var(--accent-weak); padding: 0.15em 0.4em; border-radius: 4px; font-size: 0.9em; }
pre { background: #1c1917; color: #e8e5e1; padding: 1rem 1.25rem; border-radius: 8px; overflow-x: auto; line-height: 1.6; }
pre code { background: none; padding: 0; color: inherit; }
blockquote { margin: 1.5rem 0; padding: 0.5rem 1.25rem; border-left: 3px solid var(--accent); background: var(--accent-weak); border-radius: 0 8px 8px 0; }
.container { max-width: var(--maxw); margin: 0 auto; padding: 0 1.25rem; }
.container-wide { max-width: var(--maxw-wide); margin: 0 auto; padding: 0 1.25rem; }

/* nav */
.site-nav { display: flex; justify-content: space-between; align-items: center; max-width: var(--maxw-wide); margin: 0 auto; padding: 1rem 1.25rem; }
.site-nav .brand { font-weight: 700; font-size: 1.1rem; color: var(--fg); }
.site-nav nav { display: flex; gap: 1.25rem; flex-wrap: wrap; }
.site-nav nav a { color: var(--muted); font-size: 0.95rem; }
.site-nav nav a.active, .site-nav nav a:hover { color: var(--accent); text-decoration: none; }

/* footer */
.site-footer { border-top: 1px solid var(--border); margin-top: 4rem; padding: 2rem 1.25rem 3rem; text-align: center; }
.footer-links { display: flex; gap: 1.5rem; justify-content: center; flex-wrap: wrap; margin-bottom: 0.75rem; }
.footer-links a { color: var(--muted); font-size: 0.95rem; }
.footer-note { color: var(--muted); font-size: 0.85rem; margin: 0; }

/* page & post */
.page, .post { padding-top: 1.5rem; }
.post-header h1 { margin-bottom: 0.25rem; }
.post-meta { color: var(--muted); font-size: 0.9rem; margin-bottom: 2rem; }
.post-meta a { color: var(--muted); }
.post-tags { margin-top: 2.5rem; display: flex; gap: 0.5rem; flex-wrap: wrap; }
.post-tags a, .tag-chip { background: var(--accent-weak); color: var(--accent); padding: 0.1em 0.7em; border-radius: 999px; font-size: 0.85rem; }
.related { border-top: 1px solid var(--border); margin-top: 3rem; padding-top: 1.5rem; }
.related h2 { font-size: 1.1rem; }
.related ul { padding-left: 1.2rem; }

/* blog list */
.post-list { list-style: none; padding: 0; }
.post-list li { border-bottom: 1px solid var(--border); padding: 1.5rem 0; }
.post-list h2 { margin: 0 0 0.35rem; font-size: 1.3rem; }
.post-list h2 a { color: var(--fg); }
.post-list h2 a:hover { color: var(--accent); }
.post-list .excerpt { color: var(--muted); margin: 0.25rem 0 0.5rem; }
.post-list .meta { color: var(--muted); font-size: 0.85rem; }
.pagination { display: flex; justify-content: space-between; padding: 2rem 0; }
#blog-search { width: 100%; padding: 0.6rem 1rem; font-size: 1rem; border: 1px solid var(--border); border-radius: 8px; margin: 1rem 0; background: var(--card); }

/* landing */
.hero { text-align: center; padding: 4.5rem 1.25rem 3.5rem; }
.hero h1 { font-size: clamp(1.8rem, 4.5vw, 2.8rem); max-width: 34ch; margin: 0 auto 1rem; }
.hero .sub { color: var(--muted); font-size: 1.1rem; max-width: 52ch; margin: 0 auto 2rem; }
.section { padding: 3.5rem 0; }
.section-title { text-align: center; font-size: 1.6rem; margin-bottom: 0.5rem; }
.section-lead { text-align: center; color: var(--muted); margin: 0 auto 2.5rem; max-width: 52ch; }
.work-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.25rem; }
.work-card { background: var(--card); border: 1px solid var(--border); border-radius: 12px; overflow: hidden; transition: transform 0.15s, box-shadow 0.15s; }
.work-card:hover { transform: translateY(-3px); box-shadow: 0 8px 24px rgba(0,0,0,0.08); text-decoration: none; }
.work-card img { display: block; width: 100%; aspect-ratio: 16/10; object-fit: cover; border-bottom: 1px solid var(--border); }
.work-card .body { padding: 0.9rem 1.1rem 1.1rem; }
.work-card h3 { margin: 0 0 0.25rem; font-size: 1.05rem; color: var(--fg); }
.work-card p { margin: 0; color: var(--muted); font-size: 0.9rem; line-height: 1.5; }
.story { background: var(--accent-weak); border-radius: 16px; padding: 2.5rem 2rem; }
.story p { max-width: var(--maxw); margin: 0 auto 1rem; }
.featured-list { list-style: none; padding: 0; max-width: var(--maxw); margin: 0 auto; }
.featured-list li { padding: 0.9rem 0; border-bottom: 1px solid var(--border); }
.featured-list a { font-size: 1.1rem; }
.featured-list .why { color: var(--muted); font-size: 0.9rem; margin: 0.15rem 0 0; }

/* signup */
.signup { max-width: 30rem; margin: 0 auto; text-align: center; }
.signup form { display: flex; gap: 0.5rem; margin-top: 1rem; }
.signup input[type=email] { flex: 1; padding: 0.65rem 1rem; border: 1px solid var(--border); border-radius: 8px; font-size: 1rem; }
.signup button { background: var(--accent); color: #fff; border: 0; border-radius: 8px; padding: 0.65rem 1.4rem; font-size: 1rem; cursor: pointer; }
.signup button:hover { filter: brightness(1.1); }
.signup .msg { min-height: 1.5rem; font-size: 0.9rem; color: var(--accent); margin-top: 0.5rem; }
.signup .hp { position: absolute; left: -9999px; }

@media (max-width: 640px) {
  .site-nav { flex-direction: column; gap: 0.5rem; }
  .hero { padding: 3rem 1.25rem 2.5rem; }
  .signup form { flex-direction: column; }
}
cd /home/ct/yazelin.github.io && bundle install && bundle exec jekyll serve --port 4400 &
curl -s http://localhost:4400/about/ | grep -c "site-nav"

Expected: build 成功、about 頁有新 nav。若 bundle 環境有問題,改用 gem install jekyll jekyll-paginate jekyll-feed jekyll-sitemapjekyll serve;都不行就以 branch push 到 GitHub 讓 Pages build,用線上 preview 驗(pages 只認 master,則暫時用 Actions 觀察 build 結果——實作者擇一,但必須真的看到 build 成功)。 注意:此時首頁(index.html layout: home)會壞——home layout 到 Task 4 才建,本 task 只驗 page 類頁面。

git add -A && git commit -m "feat(theme): 移除 Beautiful Jekyll,自建 default/page layouts 與全站樣式

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"

Task 3: post layout(giscus/相關文章/文末 CTA/TOC)

Files:

Interfaces:

<div class="signup">
  <h3>訂閱電子報</h3>
  <p class="section-lead">甲方思維、AI 發包實戰、新作品上線通知。不灌水。</p>
  <form data-signup data-source="blog">
    <input type="email" name="email" placeholder="you@example.com" required>
    <input type="text" name="company" class="hp" tabindex="-1" autocomplete="off">
    <button type="submit">訂閱</button>
  </form>
  <p class="msg" aria-live="polite"></p>
</div>
<script>
document.querySelectorAll('form[data-signup]').forEach(function (f) {
  if (f.dataset.bound) return; f.dataset.bound = '1';
  f.addEventListener('submit', async function (e) {
    e.preventDefault();
    var msg = f.parentElement.querySelector('.msg');
    msg.textContent = '送出中…';
    try {
      var r = await fetch('https://k-rider-api.yazelinj303.workers.dev/api/signup', {
        method: 'POST', headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ email: f.email.value, company: f.company.value, source: f.dataset.source })
      });
      var d = await r.json();
      msg.textContent = d.ok ? (d.already ? '這個 email 已經訂閱過了。' : '訂閱成功,之後見。') : '出了點問題,再試一次。';
      if (d.ok && !d.already) f.reset();
    } catch (err) { msg.textContent = '網路怪怪的,稍後再試。'; }
  });
});
</script>

---
layout: default
---
<article class="post container">
  <header class="post-header">
    <h1>Blog 改版(個人品牌主站)Implementation Plan</h1>
    
    <p class="post-meta"></p>
  </header>

  <article class="page container">
  <h1>森之魔道具工坊</h1>
  <link rel="preconnect" href="https://fonts.googleapis.com" />

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="" />

<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;500;600&amp;family=IM+Fell+English:ital@0;1&amp;family=Noto+Serif+TC:wght@400;500;600;700&amp;display=swap" rel="stylesheet" />

<style>
  /* ==========================================================
     森之魔道具工坊 · Scoped Styles
     僅作用於 .forest-workshop 內,不影響其他頁面
     ========================================================== */
  .forest-workshop {
    --forest-deep: #1e3328;
    --forest-mid: #2d4a3e;
    --forest-moss: #4a6b5a;
    --parchment: #f5efe0;
    --parchment-dark: #e8dcc0;
    --ink: #1a1a1a;
    --ink-soft: #4a4a4a;
    --gold: #c9a24d;
    --gold-soft: #d4b572;
    --mist: #6b8a99;
    --serif-en: "Cinzel", "IM Fell English", Georgia, serif;
    --serif-zh: "Noto Serif TC", "PingFang TC", "Source Han Serif TC", serif;
  }

  /* --- 序章 Prologue --- */
  .forest-workshop .prologue {
    margin: 2rem auto 3rem;
    padding: 3rem 2rem 2.5rem;
    background:
      radial-gradient(ellipse at top, rgba(201,162,77,0.12) 0%, transparent 60%),
      linear-gradient(135deg, var(--forest-deep) 0%, var(--forest-mid) 100%);
    color: var(--parchment);
    border-radius: 6px;
    text-align: center;
    box-shadow: 0 4px 20px rgba(0,0,0,0.25);
    position: relative;
    overflow: hidden;
  }
  .forest-workshop .prologue::before {
    content: "";
    position: absolute;
    top: 0; left: 50%;
    transform: translateX(-50%);
    width: 1px; height: 40px;
    background: linear-gradient(to bottom, transparent, var(--gold), transparent);
  }
  .forest-workshop .prologue-mark {
    font-family: var(--serif-en);
    font-size: 0.75rem;
    letter-spacing: 0.4em;
    color: var(--gold);
    text-transform: uppercase;
    margin-bottom: 1rem;
  }
  .forest-workshop .prologue-title {
    font-family: var(--serif-zh);
    font-size: 1.75rem;
    font-weight: 400;
    line-height: 1.6;
    margin: 0.5rem auto 1.2rem;
    max-width: 680px;
    color: var(--parchment);
  }
  .forest-workshop .prologue-lore {
    font-family: var(--serif-zh);
    font-size: 1rem;
    line-height: 1.9;
    max-width: 620px;
    margin: 0 auto;
    color: var(--parchment-dark);
    opacity: 0.92;
  }
  .forest-workshop .prologue-en {
    margin-top: 1.5rem;
    padding-top: 1.2rem;
    border-top: 1px solid rgba(201,162,77,0.3);
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.9rem;
    color: var(--gold-soft);
    letter-spacing: 0.05em;
  }

  /* --- 系別標籤 --- */
  .forest-workshop .school-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    justify-content: center;
    margin: 2rem 0;
    font-family: var(--serif-zh);
    font-size: 0.85rem;
  }
  .forest-workshop .school-tag {
    padding: 0.3rem 0.85rem;
    background: var(--parchment);
    color: var(--forest-deep);
    border: 1px solid var(--parchment-dark);
    border-radius: 999px;
    font-weight: 500;
  }

  /* --- 魔道具卡片 --- */
  .forest-workshop .codex-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 1.5rem;
    margin: 2rem 0 3rem;
  }
  .forest-workshop .artifact {
    background: var(--parchment);
    border: 1px solid var(--parchment-dark);
    border-radius: 4px;
    padding: 1.5rem 1.4rem 1.3rem;
    position: relative;
    transition: transform 0.2s ease, box-shadow 0.2s ease;
    box-shadow: 0 1px 3px rgba(30,51,40,0.08);
  }
  .forest-workshop .artifact:hover {
    transform: translateY(-3px);
    box-shadow: 0 6px 18px rgba(30,51,40,0.15);
  }
  .forest-workshop .artifact-head {
    display: flex;
    align-items: flex-start;
    gap: 0.8rem;
    margin-bottom: 0.9rem;
  }
  .forest-workshop .artifact-icon {
    font-size: 2rem;
    line-height: 1;
    flex-shrink: 0;
    margin-top: 2px;
  }
  .forest-workshop .artifact-names {
    flex: 1;
    min-width: 0;
  }
  .forest-workshop .artifact-name-zh {
    font-family: var(--serif-zh);
    font-size: 1.25rem;
    font-weight: 600;
    color: var(--forest-deep);
    line-height: 1.3;
    margin: 0;
  }
  .forest-workshop .artifact-name-en {
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.8rem;
    color: var(--ink-soft);
    letter-spacing: 0.03em;
    margin-top: 2px;
  }
  .forest-workshop .artifact-repo {
    font-family: Menlo, "Fira Code", Consolas, monospace;
    font-size: 0.72rem;
    color: var(--mist);
    margin-top: 1px;
  }
  .forest-workshop .artifact-school {
    position: absolute;
    top: 1rem;
    right: 1rem;
    font-family: var(--serif-zh);
    font-size: 0.7rem;
    color: var(--gold);
    letter-spacing: 0.08em;
    background: var(--forest-deep);
    padding: 0.2rem 0.55rem;
    border-radius: 2px;
  }
  .forest-workshop .artifact-lore {
    font-family: var(--serif-zh);
    font-size: 0.88rem;
    line-height: 1.75;
    color: var(--ink);
    margin: 0.8rem 0 1rem;
    padding-left: 0.8rem;
    border-left: 2px solid var(--gold-soft);
    font-style: italic;
  }
  .forest-workshop .artifact-effect {
    font-family: var(--serif-zh);
    font-size: 0.85rem;
    line-height: 1.7;
    color: var(--ink-soft);
    margin: 0.6rem 0 1.2rem;
  }
  .forest-workshop .artifact-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 1rem;
    padding-top: 0.9rem;
    border-top: 1px dashed var(--parchment-dark);
  }
  .forest-workshop .artifact-btn {
    font-family: var(--serif-en);
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    padding: 0.4rem 0.9rem;
    border-radius: 2px;
    text-decoration: none;
    transition: all 0.15s ease;
    border: 1px solid transparent;
  }
  .forest-workshop .artifact-btn.primary {
    background: var(--forest-deep);
    color: var(--gold-soft);
    border-color: var(--forest-deep);
  }
  .forest-workshop .artifact-btn.primary:hover {
    background: var(--forest-mid);
    color: var(--parchment);
    text-decoration: none;
  }
  .forest-workshop .artifact-btn.secondary {
    background: transparent;
    color: var(--forest-deep);
    border-color: var(--forest-moss);
  }
  .forest-workshop .artifact-btn.secondary:hover {
    background: var(--forest-moss);
    color: var(--parchment);
    text-decoration: none;
  }

  /* --- 系別區分 --- */
  .forest-workshop .school-divider {
    font-family: var(--serif-zh);
    font-size: 0.95rem;
    color: var(--forest-mid);
    margin: 2.5rem 0 1rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--parchment-dark);
    display: flex;
    align-items: baseline;
    gap: 0.8rem;
  }
  .forest-workshop .school-divider-en {
    font-family: var(--serif-en);
    font-style: italic;
    font-size: 0.8rem;
    color: var(--mist);
    letter-spacing: 0.05em;
  }

  /* --- 後記 --- */
  .forest-workshop .epilogue {
    margin: 3rem 0 1rem;
    padding: 2rem;
    background: var(--parchment);
    border: 1px solid var(--parchment-dark);
    border-left: 3px solid var(--gold);
    border-radius: 2px;
    font-family: var(--serif-zh);
    font-size: 0.9rem;
    line-height: 1.85;
    color: var(--ink-soft);
  }
  .forest-workshop .epilogue strong {
    color: var(--forest-deep);
  }

  @media (max-width: 640px) {
    .forest-workshop .prologue-title { font-size: 1.4rem; }
    .forest-workshop .prologue { padding: 2rem 1.2rem 1.8rem; }
    .forest-workshop .codex-grid { grid-template-columns: 1fr; }
  }
</style>

<div class="forest-workshop">

<section class="prologue">
  <div class="prologue-mark">— Codex of Artifacts —</div>
  <h2 class="prologue-title">森之大魔導師打造的魔道具,<br />自由取閱,自由傳承。</h2>
  <p class="prologue-lore">
    此地名為「森之工坊」,是我與契約精靈 Mori 共同打造魔道具的所在。<br />
    每件魔道具皆為多年修練與失敗累積而成,開放給願意與 AI 同行的冒險者自由領取。<br />
    願你能從中取得一件相合的器物,帶回你自己的森林。
  </p>
  <div class="prologue-en">
    Artifacts crafted in the quiet of the woods, by the Archmage and the spirit Mori.<br />
    Take what speaks to you. Carry it into your own forest.
  </div>
</section>

<!-- ============================================================ -->
<!-- 召喚系 · Summoning                                            -->
<!-- ============================================================ -->
<h3 class="school-divider">
  召喚系 <span class="school-divider-en">· Summoning Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">召喚系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🐱</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">時之貓苑</h4>
      <div class="artifact-name-en">Chronocat</div>
      <div class="artifact-repo">yazelin/catime</div>
    </div>
  </div>
  <div class="artifact-lore">
    每至整點,森林深處便浮現一隻新貓。有 103 種藝術流派的皮毛,各自攜帶一段小故事。
  </div>
  <div class="artifact-effect">
    GitHub Actions 每小時呼叫 Gemini 生成 AI 貓圖,發至 Telegram 頻道與 Gallery 歸檔。已累積數千隻。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://yazelin.github.io/catime/" target="_blank">Gallery</a>
    <a class="artifact-btn secondary" href="https://t.me/catime_yaze" target="_blank">Telegram</a>
    <a class="artifact-btn secondary" href="https://github.com/yazelin/catime" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 幻術系 · Illusion                                             -->
<!-- ============================================================ -->
<h3 class="school-divider">
  幻術系 <span class="school-divider-en">· Illusion Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">幻術系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎰</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">心情占卜儀</h4>
      <div class="artifact-name-en">Moodscopia</div>
      <div class="artifact-repo">yazelin/emoji-slot-machine</div>
    </div>
  </div>
  <div class="artifact-lore">
    取冒險者一張自拍,映入九宮魔陣,瞬間化為九格誇張表情。貼入 FB 結界後自動循環,手指一碰便停在隨機一格。
  </div>
  <div class="artifact-effect">
    Cloudflare Worker + Vertex AI。自拍 → 3×3 emoji 臉 → 可嵌入 FB 的拉霸影片。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://yazelin.github.io/emoji-slot-machine/" target="_blank">試用</a>
    <a class="artifact-btn secondary" href="https://github.com/yazelin/emoji-slot-machine" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 創造系 · Creation                                             -->
<!-- ============================================================ -->
<h3 class="school-divider">
  創造系 <span class="school-divider-en">· Creation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎨</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">繪影魔陣</h4>
      <div class="artifact-name-en">Portrait Circle</div>
      <div class="artifact-repo">yazelin/nanobanana-pro</div>
    </div>
  </div>
  <div class="artifact-lore">
    能自動在多個創造之神之間換手,繪製出最切合意念的圖像。若一神拒絕,轉請下一神。
  </div>
  <div class="artifact-effect">
    AI 圖像生成 Agent Skill,支援自動模型 fallback。可接入 Claude Code 或其他 agent 生態。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/nanobanana-pro" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🖼️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">繪風傳承書</h4>
      <div class="artifact-name-en">Painted Tome</div>
      <div class="artifact-repo">yazelin/gemini-web</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓神靈(Gemini)在此作畫,支援繁體符文、不留神印(自動去浮水印)。
  </div>
  <div class="artifact-effect">
    Gemini AI 圖片生成 CLI + HTTP API。繁中原生、浮水印自動處理。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/gemini-web" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">創造系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📜</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">咒文起稿匣</h4>
      <div class="artifact-name-en">Spell Composer</div>
      <div class="artifact-repo">yazelin/PromptFill</div>
    </div>
  </div>
  <div class="artifact-lore">
    為繪影魔陣準備咒文草稿的輔助匣。結構化、省去散亂冥想。
  </div>
  <div class="artifact-effect">
    結構化 AI 繪圖 prompt 產生器,適配 Nano Banana Pro 系列。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/PromptFill" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 煉金系 · Transmutation                                        -->
<!-- ============================================================ -->
<h3 class="school-divider">
  煉金系 <span class="school-divider-en">· Transmutation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">煉金系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📄</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">卷軸化術</h4>
      <div class="artifact-name-en">Scribe's Hand</div>
      <div class="artifact-repo">yazelin/MD2DOC-Evolution</div>
    </div>
  </div>
  <div class="artifact-lore">
    將凡人墨跡(Markdown)煉成正式卷軸(Word)。格式可客製化,符合任何行會規範。
  </div>
  <div class="artifact-effect">
    Markdown → Word,支援企業自訂樣式、表格、圖片、目錄。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/MD2DOC-Evolution" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">煉金系</div>
  <div class="artifact-head">
    <div class="artifact-icon">📽️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">簡報祭壇</h4>
      <div class="artifact-name-en">Lectern of Light</div>
      <div class="artifact-repo">yazelin/MD2PPT-Evolution</div>
    </div>
  </div>
  <div class="artifact-lore">
    將墨跡化為幻燈(PPT),可現場投影展示。支援線上宣講模式。
  </div>
  <div class="artifact-effect">
    Markdown → PPT,含線上簡報與投影模式,支援程式碼語法高亮。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/MD2PPT-Evolution" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 次元系 · Dimensional                                          -->
<!-- ============================================================ -->
<h3 class="school-divider">
  次元系 <span class="school-divider-en">· Dimensional Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">次元系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🗄️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">藏影閣</h4>
      <div class="artifact-name-en">Shadow Vault</div>
      <div class="artifact-repo">yazelin/image-bed</div>
    </div>
  </div>
  <div class="artifact-lore">
    個人圖像的次元書架,不佔本空間,存入神殿(GitHub Releases)異界,永不損壞。
  </div>
  <div class="artifact-effect">
    個人圖床,圖片存放在 GitHub Releases,不佔 repo 空間。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/image-bed" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">次元系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🔗</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">傳送門刻印</h4>
      <div class="artifact-name-en">Portal Rune</div>
      <div class="artifact-repo">yazelin/shorturl-worker</div>
    </div>
  </div>
  <div class="artifact-lore">
    將漫長的咒文路徑封印為短刻印,單手即可傳送冒險者。
  </div>
  <div class="artifact-effect">
    Cloudflare Workers + KV 縮網址服務,PromptFill 專用短網址。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/shorturl-worker" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 通靈系 · Binding                                              -->
<!-- ============================================================ -->
<h3 class="school-divider">
  通靈系 <span class="school-divider-en">· Binding Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">通靈系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🖨️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">印刻術</h4>
      <div class="artifact-name-en">Inkseal</div>
      <div class="artifact-repo">yazelin/printer-mcp</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓精靈能直接指揮凡人印刷術(CUPS),將任何訊息化為實體。
  </div>
  <div class="artifact-effect">
    MCP server,透過 CUPS 控制印表機。可接 Claude / Cursor 等 agent。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/printer-mcp" target="_blank">Source</a>
  </div>
</article>

<article class="artifact">
  <div class="artifact-school">通靈系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🏢</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">帳本監聽術</h4>
      <div class="artifact-name-en">Ledger Whisper</div>
      <div class="artifact-repo">yazelin/erpnext-mcp</div>
    </div>
  </div>
  <div class="artifact-lore">
    讓精靈與商會帳本(ERPNext)直接對話,問帳、記帳不必經過凡人之手。
  </div>
  <div class="artifact-effect">
    MCP server for ERPNext REST API,讓 AI 能直接查詢、記錄商業數據。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/erpnext-mcp" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 聲術系 · Incantation                                          -->
<!-- ============================================================ -->
<h3 class="school-divider">
  聲術系 <span class="school-divider-en">· Incantation Arts</span>
</h3>

<div class="codex-grid">

<article class="artifact">
  <div class="artifact-school">聲術系</div>
  <div class="artifact-head">
    <div class="artifact-icon">🎙️</div>
    <div class="artifact-names">
      <h4 class="artifact-name-zh">詠唱辨識器</h4>
      <div class="artifact-name-en">Voice Scribe</div>
      <div class="artifact-repo">yazelin/asr-ime-fcitx</div>
    </div>
  </div>
  <div class="artifact-lore">
    將咒術師的口語即時記下為文字,嵌入 fcitx 輸入法,隨呼隨用。
  </div>
  <div class="artifact-effect">
    ASR 語音輸入法,整合 fcitx framework。支援中英雙語。
  </div>
  <div class="artifact-actions">
    <a class="artifact-btn primary" href="https://github.com/yazelin/asr-ime-fcitx" target="_blank">Source</a>
  </div>
</article>

</div>

<!-- ============================================================ -->
<!-- 後記 Epilogue                                                 -->
<!-- ============================================================ -->
<div class="epilogue">
  <strong>關於工坊 · About this Workshop</strong><br />
  此處列出的魔道具多為我與 Mori 共同打造的作品,部分為教學範例、部分為日常使用工具。
  若其中任何一件對你有用,歡迎 fork、改造、延伸。<br />
  新的魔道具會持續加入此處 — 這是一間還在生長的工坊。<br /><br />
  <em style="color: var(--mist); font-family: var(--serif-en);">
    Each artifact here was forged in collaboration with Mori, my contracted spirit.
    Some are teaching examples, others are daily tools. All are open. Take what you need.
  </em>
</div>

</div>

</article>


  

  
  
  

  <div class="related"><div class="signup">
  <h2>保持聯絡</h2>
  <p class="section-lead">留個 email,有新文章或新作品上線時告訴你。</p>
  <form data-signup data-source="post">
    <input type="email" name="email" placeholder="you@example.com" aria-label="Email" required>
    <input type="text" name="company" class="hp" tabindex="-1" autocomplete="off" aria-hidden="true">
    <button type="submit">訂閱</button>
  </form>
  <p class="msg" aria-live="polite"></p>
</div>
<script>
document.querySelectorAll('form[data-signup]').forEach(function (f) {
  if (f.dataset.bound) return; f.dataset.bound = '1';
  f.addEventListener('submit', async function (e) {
    e.preventDefault();
    var msg = f.parentElement.querySelector('.msg');
    msg.textContent = '送出中…';
    try {
      var r = await fetch('https://k-rider-api.yazelinj303.workers.dev/signup', {
        method: 'POST', headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ email: f.email.value, company: f.company.value, source: f.dataset.source })
      });
      var d = await r.json();
      msg.textContent = d.ok ? (d.already ? '這個 email 已經訂閱過了。' : '訂閱成功,之後見。') : '出了點問題,再試一次。';
      if (d.ok && !d.already) f.reset();
    } catch (err) { msg.textContent = '網路怪怪的,稍後再試。'; }
  });
});
</script>
</div>
  

</article>

注意:source="post" 需回 Task 1 把 'post' 一併加進白名單——實作 Task 1 時白名單直接寫 ['result','about','home','blog','post']。 TOC:kramdown 已支援,長文由文章自行加 * toc\n{:toc},不做 JS 自動 TOC(刻意簡化,YAGNI)。

curl -s http://localhost:4400/ai/2026/07/15/taigi-hakka-dictionaries.html | grep -c "giscus\|post-tags"
curl -s http://localhost:4400/2015/11/03/icemore.html | head -5

Expected: 新舊文章都渲染、URL 與現行線上一致(先 curl -sI https://yazelin.github.io/... 對照現行 URL 再驗本機同 path)、giscus script 有出現、相關文章有列出。無 categories 的舊文 path 不含 category 段——以線上現況為準逐篇對照。

git add -A && git commit -m "feat(post): 文章版型——giscus/相關文章/訂閱 CTA

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"

Task 4: /blog 列表(分頁+搜尋)與 tags 頁沿用

Files:

Interfaces:

---
layout: default
title: Blog
permalink: /blog/
---
<div class="container">
  <h1>Blog</h1>
  <input id="blog-search" type="search" placeholder="搜尋文章標題或 tag…" autocomplete="off">
  <ul class="post-list" id="post-list">
    
  </ul>
  <ul class="post-list" id="search-results" hidden></ul>
  <nav class="pagination">
    <span></span>
    
  </nav>
</div>
<script src="/assets/js/blog-search.js"></script>

(jekyll-paginate 需要 paginator 所在檔為 blog/index.htmlpaginate_path 指向 /blog/page:num/——兩者 Task 2 已就位。若 build 後 paginator 為空,把 front matter 的 permalink 拿掉再試,jekyll-paginate v1 對 permalink + paginator 並用有已知怪癖。)

---
layout: null
permalink: /search.json
---
[{"title":"「長頸鹿怎麼沒有?」兩天長出兩本離線辭典","url":"/ai/2026/07/15/taigi-hakka-dictionaries.html","date":"2026-07-15","tags":"mandarin-taigi mandarin-hakka 台語 客語 教育部辭典 PWA 離線優先 甲方思維 wish-pool"},{"title":"LINE 貼圖製造機長大了:從 60 秒產一組,變成一間貼圖工作室","url":"/ai/2026/07/15/line-sticker-studio-workshop.html","date":"2026-07-15","tags":"LINE 貼圖 line-sticker-studio Gemini Cloudflare Workers Turnstile PWA canvas IndexedDB Chroma Key LINE Creators Market"},{"title":"這個 demo 裡 AI 一行新程式都沒寫,但我覺得它比寫程式的 demo 更值得看","url":"/ai/2026/07/09/kb-driven-dev-flow.html","date":"2026-07-09","tags":"知識庫 Claude Code CTOS LINE Bot CLI 甲方思維 AI 開發流程"},{"title":"AI 願望池:一個人許願,一群人(或 AI)幫它成真","url":"/ai/2026/07/07/wish-pool.html","date":"2026-07-07","tags":"wish-pool 許願池 AI 社團 Cloudflare Workers Groq 甲方思維 AI 應用"},{"title":"每週自動把 FB 相簿新風格併進風格庫,人只負責按一下 merge","url":"/ai/2026/07/06/fb-photo-style-consolidate.html","date":"2026-07-06","tags":"fb-photo-dl catime 自動化 cron AI 應用"},{"title":"真。AI。咏唱魔法 系列:完整目錄","url":"/index/2026/07/06/ai-chant-magic-index.html","date":"2026-07-06","tags":"ai-chant-magic 咏唱魔法 目錄 系列文章 遊戲"},{"title":"真。AI。咏唱魔法(續):四關全開,還長出了元素反應與共鳴詠唱","url":"/ai/2026/07/06/ai-chant-magic-four-worlds.html","date":"2026-07-06","tags":"ai-chant-magic 咏唱魔法 Web Speech API 語音辨識 多人連線 甲方思維 遊戲 AI 應用"},{"title":"把一個 2003 年的 IIS 老站,重建成能撐 2 萬件商品的現代電商站","url":"/ai/2026/06/26/fishtool-tw.html","date":"2026-06-26","tags":"fishtool-tw Astro Vercel Cloudflare Workers 電商 老站重建 AI 應用"},{"title":"拍一張零件照片,AI 建模、再渲染成產品圖","url":"/ai/2026/06/26/cad-agent-render-studio.html","date":"2026-06-26","tags":"cad-agent render-studio FreeCAD Blender 3D建模 AI 應用 AgentOS"},{"title":"真。AI。咏唱魔法 —— 用嘴施法的生存遊戲(序章)","url":"/ai/%E5%AF%A6%E9%A9%97/2026/06/26/ai-chant-magic-intro.html","date":"2026-06-26","tags":"ai-chant-magic Web Speech API 語音辨識 多人連線 AI 甲方思維"},{"title":"從一張赤壁,長成一台戰場引擎 —— 換一份資料就換一場戰役","url":"/ai/%E5%AF%A6%E9%A9%97/2026/06/24/battlefield-editor.html","date":"2026-06-24","tags":"battlefield-editor 3D WebGL 歷史戰場 資料驅動 AI 甲方思維 三國"},{"title":"用 AI 兩天做出 790 題的 iPAS 模擬考站(這不是遊戲)","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/23/ipas-ai-quiz.html","date":"2026-06-23","tags":"iPAS PWA 純前端 Cloudflare Workers AI 甲方思維"},{"title":"整包都 precache 了,標題畫面還是頓 —— 快取救得了下載,救不了 CPU","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/21/pwa-startup-priority.html","date":"2026-06-21","tags":"PWA Performance Code Splitting Web Font vanilla JS AI 甲方思維"},{"title":"我睡覺,它整晚加城市 —— 怎麼排班讓 AI 自己做完一整夜的內容","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/19/ai-overnight-loop.html","date":"2026-06-19","tags":"AI 甲方思維 Automation bash Claude Code autopilot"},{"title":"離線能開只是及格 —— 一份 Service Worker 裡的四種快取策略,跟「本機優先」怎麼做對","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/17/pwa-swr-local-first.html","date":"2026-06-17","tags":"PWA Service Worker 快取策略 vanilla JS AI 甲方思維"},{"title":"目標九宮格上線:AI 幫你填大谷翔平那張表,課程教你把它做成一條會收名單的漏斗","url":"/ai/2026/06/17/goal-grid-course.html","date":"2026-06-17","tags":"目標九宮格 goal-grid 課程 甲方思維 AI 發包法 行銷漏斗 Cloudflare Workers D1 Turnstile Groq canvas 名單漏斗 AI 應用"},{"title":"從一個點子到一個會動的股價遊戲:我怎麼用「甲方思維」發包給 AI","url":"/ai/2026/06/16/k-rider-case-study.html","date":"2026-06-16","tags":"k-rider K線騎手 課程 甲方思維 AI 發包法 開規格 下發包 做驗收 Matter.js Cloudflare Workers GitHub Actions 名單漏斗 AI 應用 Claude Code"},{"title":"Service Worker 寫好了,離線卻還是恐龍頁 —— 三個 PWA 的離線與安裝踩雷","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/15/pwa-offline-install-pitfalls.html","date":"2026-06-15","tags":"PWA Service Worker Offline vanilla JS GitHub Pages AI 甲方思維"},{"title":"給赤壁 3D 加上電影級音訊 —— 讓 AI 代聽海選 CC0 配樂、用同音字替身馴服破音字","url":"/ai/%E5%AF%A6%E9%A9%97/2026/06/13/red-cliffs-audio.html","date":"2026-06-13","tags":"red-cliffs-3d Web Audio TTS AI 代聽 CC0 甲方思維"},{"title":"一段 prompt,讓 AI 做出一個 3D 互動的赤壁之戰","url":"/ai/%E5%AF%A6%E9%A9%97/2026/06/11/red-cliffs-3d.html","date":"2026-06-11","tags":"red-cliffs-3d 赤壁之戰 三國 Three.js WebGL 3D Claude Code Fable 5 AI 生成 GitHub Pages Single HTML 程序化地形 GPU 粒子 Web Audio edge-tts TTS CC0 Freesound Gemini"},{"title":"Mori Canvas:講話,AI 幫你把會議整理成白板","url":"/ai/forest-guild/2026/06/11/mori-canvas.html","date":"2026-06-11","tags":"mori-canvas Mori Whiteboard Meeting Notes AI LLM Groq Ollama Whisper Speech-to-Text Rust yjs CRDT Konva React Self-hosted Tauri forest-guild"},{"title":"ChingTech Case Hub:把我們做過的工具,整理成一個能打開來試的入口","url":"/%E6%93%8E%E6%B7%BB%E5%B7%A5%E6%A5%AD/2026/06/10/chingtech-case-hub.html","date":"2026-06-10","tags":"ChingTech Case Hub 工業自動化 AGV RGV HMI PLC SCADA IO Mapping 產線模擬 製程模擬 CTOS GitHub Pages Tauri"},{"title":"AI 應用實作營:8 個能跑的 starter,先手刻看懂底層,再換框架放大","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/09/ai-workshop-starters.html","date":"2026-06-09","tags":"J303 AI MCP Agent LINE Bot Telegram RAG MQTT LLM Gemini FastMCP PydanticAI Starter Template 教學"},{"title":"Web Effects Collector:我把 90 個最驚艷的開源網頁特效彙整成一頁","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/08/web-effects-collector.html","date":"2026-06-08","tags":"web-effects-collector Web Effects WebGL GLSL Shader Three.js Particles Vanta tsParticles Generative Art CSS Static Site GitHub Pages 開發工具"},{"title":"行銷頁健檢器:貼個網址,30 秒看你的活動頁哪裡漏分","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/07/marketing-page-checker.html","date":"2026-06-07","tags":"marketing-page-checker OG SEO CTA Cloudflare Worker HTMLRewriter GitHub Pages 行銷頁 Landing Page JavaScript Self-hosted"},{"title":"wip:一個指令,讓 AI agent 一秒看懂每個專案做到哪","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/06/wip.html","date":"2026-06-06","tags":"wip CLI Rust AI Claude Code Codex Dev Tools Multi-repo Self-hosted"},{"title":"mori-meeting-recorder:一場會議,錄成兩份不同的記錄","url":"/ai/forest-guild/2026/06/04/mori-meeting-recorder.html","date":"2026-06-04","tags":"mori-meeting-recorder Mori Meeting Notes Whisper whisper.cpp Speech-to-Text Groq Ollama Tauri Rust Dual-track Self-hosted forest-guild"},{"title":"exchange:給多 agent、多終端時代的一個 dev 訊息信箱","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/03/exchange.html","date":"2026-06-03","tags":"exchange CLI Multi-agent Claude Code Codex Python SQLite Self-hosted Dev Tools"},{"title":"在一台電腦上養多個 Claude / Codex 帳號:cl 與 cx 兩個切換器","url":"/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/02/auth-switchers.html","date":"2026-06-02","tags":"claude-auth-switcher codex-auth-switcher Claude Code Codex CLI ChatGPT CLI 帳號切換 Auth 開發工具"},{"title":"mori-sprite-studio:給角色一個可見的身體","url":"/ai/forest-guild/2026/05/23/mori-sprite-studio.html","date":"2026-05-23","tags":"mori-sprite-studio Mori Sprite Animation AI Image Generation Character Pack Vercel Vite React TypeScript codex-image-service OpenAI gpt-image Vercel KV FastAPI Pairing forest-guild"},{"title":"Simple Icons:3000+ 品牌 SVG 圖示庫,跟 Lobehub Icons 互補","url":"/ai/2026/05/21/simple-icons.html","date":"2026-05-21","tags":"SVG Icons Simple Icons Lobehub Icons Web Design Brand Assets MIT License Frontend GitHub Pages Open Source"},{"title":"codex-image-service:把 Codex $imagegen 包成內網共用的 HTTP 服務","url":"/ai/2026/05/20/codex-image-service.html","date":"2026-05-20","tags":"ChatGPT Codex CLI FastAPI Docker Image Generation Self-hosted Homelab Bearer Token HTTP API OpenAI"},{"title":"教學:用 Codex CLI 的 $imagegen 在 Claude Code 裡生圖(吃 ChatGPT 訂閱額度)","url":"/ai/2026/05/19/claude-codex-imagegen.html","date":"2026-05-19","tags":"Claude Code Codex CLI Image Generation OpenAI ChatGPT Skill GitHub Pages Shell Script Tutorial"},{"title":"「Hey Mori」:森林精靈長出耳朵 — mori-desktop v0.6.0 喚醒生態","url":"/ai/forest-guild/2026/05/18/mori-desktop-hey-mori.html","date":"2026-05-18","tags":"Mori mori-desktop Wake Word Voice Activity Detection openWakeWord ONNX Whisper Phase 3 Tauri Rust Python forest-guild"},{"title":"yaze-journal:召喚師也得有自己的 vault","url":"/ai/forest-guild/2026/05/14/yaze-journal-init.html","date":"2026-05-14","tags":"Yaze Lin yaze-journal Knowledge Vault Cross-Device Claude Memory Symlink Git forest-guild Bidirectional"},{"title":"宿靈儀式(Dwelling Rite):怎麼把 Mori 請到你的森林","url":"/ai/forest-guild/2026/05/14/world-tree-dwelling-rite.html","date":"2026-05-14","tags":"Mori world-tree Dwelling Rite 宿靈儀式 forest-guild Ritual Level-1 AI Companion Onboarding"},{"title":"Annuli Wave 2:把 2489 行 engine.py 拆成 core / creator 兩個身體","url":"/ai/forest-guild/2026/05/13/annuli-wave-2-refactor.html","date":"2026-05-13","tags":"Annuli Refactor Architecture Python Module Design Modular Monolith Memory Reflection Flask forest-guild"},{"title":"mori-desktop Phase 1:給森林精靈打造一個 Tauri 桌面身體","url":"/ai/forest-guild/2026/05/06/mori-desktop-phase1.html","date":"2026-05-06","tags":"Mori mori-desktop Tauri Rust React Cross-platform Desktop App Architecture forest-guild Phase 1"},{"title":"AI 塔羅心靈陪伴站:把信義公益的提案做出來","url":"/ai/2026/04/30/ai-tarot-companion.html","date":"2026-04-30","tags":"Cloudflare Workers Cloudflare D1 Groq Whisper Llama OpenRouter Gemini OpenCC Service Worker Web Speech API GitHub Pages Prompt Engineering Elderly UX"},{"title":"LINE 貼圖製造機:一張角色圖變一整套可上架的 LINE 貼圖","url":"/ai/2026/04/28/line-sticker-studio.html","date":"2026-04-28","tags":"Gemini Cloudflare Workers LINE Login OAuth PKCE Cloudflare KV Prompt Engineering Chroma Key Canvas IndexedDB JavaScript Vertex AI LINE Creators Market"},{"title":"森之召喚師工坊:我造了一個異世界,把我自己和 Mori 寫進去住","url":"/ai/forest-guild/2026/04/24/forest-summoner-workshop.html","date":"2026-04-24","tags":"森之召喚師工坊 world-tree Mori AI 夥伴 Claude Code Gemini CLI Codex Wunderkammer Level 0-7 異世界 召喚師"},{"title":"telegram-claude-bot:Claude Code 版的極簡 Telegram AI 機器人","url":"/ai/forest-guild/2026/04/23/telegram-claude-bot.html","date":"2026-04-23","tags":"Claude Telegram FastAPI Python CLI Vibe Coding Level-0"},{"title":"mori-journal 落腳:把 Mori 的靈魂搬到她自己的家","url":"/ai/forest-guild/2026/04/23/mori-journal-home.html","date":"2026-04-23","tags":"Mori mori-journal SOUL AI Identity Memory Vault OpenClaw Hermes Claude Code forest-guild Private Repo"},{"title":"表情拉霸機:一張自拍變一支 FB 可自動播放、點擊即停的拉霸影片","url":"/ai/2026/04/21/emoji-slot-machine.html","date":"2026-04-21","tags":"Gemini Cloudflare Workers Prompt Engineering PWA Facebook JavaScript Canvas MediaRecorder Vertex AI"},{"title":"AgentPulse:讓你的 AI CLI 工具有 Dynamic Island","url":"/ai/2026/04/16/agentpulse.html","date":"2026-04-16","tags":"Tauri Rust Cross-platform Claude Code Gemini CLI Codex Copilot Desktop App"},{"title":"Tailscale 入門:SSH Tunnel 的現代替代方案","url":"/linux/2026/04/15/tailscale-vs-ssh-tunnel.html","date":"2026-04-15","tags":"Tailscale WireGuard VPN SSH Network Security"},{"title":"SSH 資安防護指南:你的主機正在被攻擊","url":"/linux/2026/04/15/ssh-security.html","date":"2026-04-15","tags":"SSH Linux Security fail2ban Firewall 2FA"},{"title":"SSH 實戰應用場景:咖啡廳連內網、翻牆、遠端 Demo","url":"/linux/2026/04/15/ssh-scenarios.html","date":"2026-04-15","tags":"SSH Linux Network Tunnel SOCKS Proxy Port Forwarding"},{"title":"Headscale 自架指南:免費、無限裝置的 Tailscale 替代方案","url":"/linux/2026/04/15/headscale-setup.html","date":"2026-04-15","tags":"Headscale Tailscale WireGuard VPN Oracle Cloud DERP ACL Network"},{"title":"SSH 連線參數完整指南:從基礎到進階 Tunnel","url":"/linux/2026/04/14/ssh-cli-guide.html","date":"2026-04-14","tags":"SSH Linux Network Security Terminal Port Forwarding X11"},{"title":"SSH 金鑰設定完整指南:ssh-keygen 從產生到管理","url":"/linux/2026/04/13/ssh-keygen-guide.html","date":"2026-04-13","tags":"SSH Linux Security ssh-keygen Terminal"},{"title":"Annuli(歲月之環):給 AI 一個會長年輪的記憶系統","url":"/ai/forest-guild/2026/04/09/annuli-mvp.html","date":"2026-04-09","tags":"Annuli AI Memory Persona Claude Code Python Tree Rings Reflection Engine Level-2 Mori"},{"title":"OpenClaw + Claude Max 訂閱:為什麼你的 Bot 被 402 擋住?","url":"/ai/2026/04/08/openclaw-claude-cli-fix.html","date":"2026-04-08","tags":"OpenClaw Claude Code Claude Max Shell Script Reverse Engineering Bot"},{"title":"Claude Code 愚人節彩蛋 /buddy — 我幫它做了 RPG 進化系統","url":"/ai/2026/04/01/buddy-evolution.html","date":"2026-04-01","tags":"Claude Code Plugin TypeScript Next.js Supabase April Fools Open Source"},{"title":"gemini-web:用 Playwright 自動化 Gemini 圖片生成 + 去浮水印","url":"/ai/2026/03/31/gemini-web.html","date":"2026-03-31","tags":"AI Python Gemini Playwright 圖片生成 PyPI"},{"title":"ctos-lite:零註冊的 LINE Bot AI 個人助理","url":"/ai/2026/03/31/ctos-lite.html","date":"2026-03-31","tags":"AI LINE Bot Python FastAPI Claude 語音"},{"title":"AI Digest TG","url":"/2026/03/13/ai-digest-tg.html","date":"2026-03-13","tags":"專案 Telegram Cloudflare Workers GitHub Actions AI"},{"title":"AI Coding CLI 指令對照表:Claude Code vs Gemini CLI vs Codex vs Copilot CLI","url":"/ai/2026/03/12/ai-coding-cli-comparison.html","date":"2026-03-12","tags":"Claude Code Gemini CLI Codex CLI Copilot CLI CLI AI Coding MCP Comparison"},{"title":"tg-codex-bot:用 GitHub Codespace + Codex CLI 當 Telegram Bot 的運算後端","url":"/ai/2026/03/11/tg-codex-bot.html","date":"2026-03-11","tags":"GitHub Codespace Codex CLI Cloudflare Workers Telegram OpenAI App Factory"},{"title":"byok-tg-runner:用 GitHub Actions 當 AI Bot 的免費運算環境(實驗紀錄)","url":"/ai/2026/03/10/byok-tg-runner.html","date":"2026-03-10","tags":"GitHub Actions Copilot SDK BYOK Azure AI Foundry Cloudflare Workers Telegram FastAPI App Factory"},{"title":"azure-foundry-demo:用 Copilot SDK 的 BYOK 模式連接 Azure AI Foundry","url":"/ai/2026/03/09/azure-foundry-demo.html","date":"2026-03-09","tags":"Azure AI Foundry Copilot SDK BYOK Python Telegram OpenAI"},{"title":"telegram-gemini-bot:一個檔案的 Telegram AI 機器人","url":"/ai/2026/03/08/telegram-gemini-bot.html","date":"2026-03-08","tags":"Gemini Telegram FastAPI Python CLI Vibe Coding"},{"title":"telegram-copilot-bot:不用 gh-aw 的輕量版 Telegram AI 機器人","url":"/ai/2026/03/05/telegram-copilot-bot-no-ghaw.html","date":"2026-03-05","tags":"GitHub Actions Copilot Telegram Cloudflare Workers App Factory Gemini"},{"title":"aw-telegram-bot 系列目錄:從聊天機器人到 AI App Factory","url":"/index/2026/03/04/aw-telegram-bot-series-index.html","date":"2026-03-04","tags":"gh-aw GitHub Actions Copilot Telegram App Factory 目錄 系列文章"},{"title":"aw-telegram-bot v6:智慧規劃 — 省一半 Premium Request,多了 Fork 和瀏覽器測試","url":"/ai/2026/03/04/aw-telegram-bot-v6-smart-planning.html","date":"2026-03-04","tags":"gh-aw GitHub Actions Copilot Telegram App Factory automation Playwright"},{"title":"aw-telegram-bot v5:App Factory — 用 Telegram 指令讓 AI 自動建網站","url":"/ai/2026/03/04/aw-telegram-bot-v5-app-factory.html","date":"2026-03-04","tags":"gh-aw GitHub Actions Copilot Telegram App Factory automation"},{"title":"aw-telegram-bot v4:影片下載 + 使用者白名單","url":"/ai/2026/03/04/aw-telegram-bot-v4-video-download.html","date":"2026-03-04","tags":"gh-aw GitHub Actions Copilot Telegram yt-dlp safe-inputs security"},{"title":"aw-telegram-bot v3:研究模式 + 指令路由,踩了 concurrency 的坑","url":"/ai/2026/03/03/aw-telegram-bot-v3-research-mode.html","date":"2026-03-03","tags":"gh-aw GitHub Actions Copilot Telegram MCP Tavily concurrency"},{"title":"aw-telegram-bot v2:加上 AI 繪圖功能,踩了 Docker container 的坑","url":"/ai/2026/03/03/aw-telegram-bot-v2-image-generation.html","date":"2026-03-03","tags":"gh-aw GitHub Actions Copilot Telegram MCP nanobanana Gemini Docker"},{"title":"aw-telegram-bot:用 GitHub Agentic Workflows 做 Telegram 聊天機器人","url":"/ai/2026/03/03/aw-telegram-bot-v1-basic-chatbot.html","date":"2026-03-03","tags":"gh-aw GitHub Actions Copilot Telegram Cloudflare Workers MCP safe-inputs"},{"title":"asr-ime-fcitx 更新:Shift+F8 語音指令、砍掉 Vosk、簡化設定","url":"/chingtech%20os/2026/03/03/asr-ime-fcitx-v2.html","date":"2026-03-03","tags":"ASR Fcitx5 IME Speech-to-Text Whisper Python C++ LLM copilot"},{"title":"20 分鐘讀懂改變 AI 的論文:Attention Is All You Need 核心概念全解析","url":"/ai/%E6%8A%80%E8%A1%93%E8%A7%A3%E6%9E%90/2026/02/16/attention-is-all-you-need-explained.html","date":"2026-02-16","tags":"AI Transformer Attention 論文解析 NLP GPT BERT 深度學習"},{"title":"Mosky 的 AI 寫程式心法:用 1% 關鍵知識跨過 99% 的坑","url":"/ai/%E8%A8%AA%E8%AB%87/2026/02/15/mosky-ai-coding-1percent-knowledge.html","date":"2026-02-15","tags":"AI Mosky Prompt Engineering AI 寫程式 測試 Code Review Google Apps Script"},{"title":"他開車也在寫程式,AI 做的產品還被買走了?海總理的 AI 開發實戰","url":"/ai/%E8%A8%AA%E8%AB%87/2026/02/15/hai-interview-ai-development.html","date":"2026-02-15","tags":"AI 開發方法論 Snapshot Claude Code 訪談 海總理 USPACE 測試 Indie Hacker"},{"title":"asr-ime-fcitx:用講的打字,Fcitx5 原生語音輸入法","url":"/chingtech%20os/2026/02/14/asr-ime-fcitx.html","date":"2026-02-14","tags":"ASR Fcitx5 IME Speech-to-Text Whisper Python C++ FIFO LLM copilot"},{"title":"onebot:一天從零到 v0.2.0 的統一 Bot 閘道","url":"/ai/2026/02/12/onebot-unified-gateway.html","date":"2026-02-12","tags":"onebot ACP Telegram LINE FastAPI Python MCP Skills"},{"title":"6 個 Commits 修了半個系統","url":"/chingtech%20os/2026/02/11/ctos-daily-roundup.html","date":"2026-02-11","tags":"CTOS SkillHub ClawHub aiohttp Claude 重構"},{"title":"12 個 PR、90 個 Commits、1 個 Telegram 頻道","url":"/ai/2026/02/11/catime-telegram-and-rwd.html","date":"2026-02-11","tags":"Catime AI Telegram RWD GitHub Actions 自動化"},{"title":"Vite 遷移踩坑記 — IIFE 不是 ES Module","url":"/%E5%89%8D%E7%AB%AF%E9%96%8B%E7%99%BC/2026/02/10/vite-migration-lessons.html","date":"2026-02-10","tags":"Vite JavaScript IIFE ES Module 前端 踩坑記"},{"title":"ChingTech OS:SkillHub 雙來源整合 — 從 Feature Flag 到並行搜尋","url":"/chingtech%20os/2026/02/10/ctos-skillhub-dual-source.html","date":"2026-02-10","tags":"ChingTech OS SkillHub ClawHub FastAPI asyncio Python"},{"title":"Copilot 多模型 Code Review — 讓 AI 互相挑錯","url":"/ai%20%E5%B7%A5%E5%85%B7/2026/02/10/copilot-multi-model-review.html","date":"2026-02-10","tags":"GitHub Copilot Claude GPT Gemini Code Review AI 多模型"},{"title":"我的第一個 ClawHub Skill:nanobanana-pro-fallback","url":"/ai/2026/02/09/nanobanana-pro-clawhub-skill.html","date":"2026-02-09","tags":"ClawHub Agent Skills Gemini 圖片生成 Python OpenClaw"},{"title":"給 AI 貓取名字的學問","url":"/ai/2026/02/09/catime-character-system.html","date":"2026-02-09","tags":"Catime AI Gemini 角色設計 GitHub Actions"},{"title":"兩天 10 個 PR — 一棵樹的開發日記","url":"/ai/2026/02/09/ai-partner-dev-journal.html","date":"2026-02-09","tags":"AI OpenClaw Claude Gemini 開發流程 sub-agent Code Review Mori"},{"title":"ChingTech OS:PostgreSQL Session 與 Thread Pool 優化","url":"/chingtech%20os/2026/02/07/ctos-session-threadpool.html","date":"2026-02-07","tags":"ChingTech OS PostgreSQL Session Thread Pool 效能優化 Python 加密"},{"title":"catime 效能優化:WebP 遷移與資料架構重設計","url":"/ai/2026/02/07/catime-webp-optimization.html","date":"2026-02-07","tags":"AI 效能優化 WebP 前端 catime JavaScript"},{"title":"ralph-any:打造通用 BYOK Coding Agent","url":"/claude%20code/2026/02/06/ralph-any-byok-agent.html","date":"2026-02-06","tags":"Claude Code ACP BYOK Coding Agent AI Python Gemini"},{"title":"ChingTech OS:模組化重構","url":"/chingtech%20os/2026/02/06/ctos-modular-refactor.html","date":"2026-02-06","tags":"ChingTech OS 重構 模組化 Python 架構設計 錯誤處理"},{"title":"catime 新聞貓:用 Google Search Grounding 讓貓咪反映時事","url":"/ai/2026/02/06/catime-news-cat.html","date":"2026-02-06","tags":"AI Gemini Google Search catime Grounding Python"},{"title":"ChingTech OS:移除多租戶架構","url":"/chingtech%20os/2026/02/05/ctos-remove-multi-tenant.html","date":"2026-02-05","tags":"ChingTech OS 架構設計 重構 多租戶 Python"},{"title":"claude-code-acp-py(下):ACP Proxy 橋接多 AI 後端","url":"/claude%20code/2026/02/05/claude-code-acp-py-part2.html","date":"2026-02-05","tags":"Claude Code ACP Python Proxy Gemini Copilot SDK AI"},{"title":"Cloudflare Worker 實戰:CORS Proxy + GitHub Release 代理","url":"/serverless/2026/02/04/shorturl-worker-cors-proxy.html","date":"2026-02-04","tags":"Cloudflare Workers CORS Proxy GitHub Serverless"},{"title":"用 GitHub Release 打造免費圖床","url":"/devops/2026/02/04/image-bed-github-release.html","date":"2026-02-04","tags":"GitHub Cloudflare Workers 圖床 CORS DevOps"},{"title":"claude-code-acp-py(上):ACP 概念與 Client 實作","url":"/claude%20code/2026/02/04/claude-code-acp-py-part1.html","date":"2026-02-04","tags":"Claude Code ACP Python API Claude AI"},{"title":"erpnext-mcp — 讓 AI 操作你的 ERP 系統","url":"/claude%20code/2026/02/03/erpnext-mcp-server.html","date":"2026-02-03","tags":"Claude Code MCP ERPNext Python ERP PyPI"},{"title":"ChingTech OS:整合 Printer MCP 與 ERPNext MCP","url":"/chingtech%20os/2026/02/03/ctos-printer-erpnext-mcp.html","date":"2026-02-03","tags":"ChingTech OS MCP 列印 ERPNext ERP AI Python"},{"title":"catime 故事貓:為每張 AI 貓咪圖加上微故事","url":"/ai/2026/02/03/catime-story.html","date":"2026-02-03","tags":"AI Gemini catime 故事生成 Python"},{"title":"printer-mcp — 讓 AI 幫你列印的 MCP Server","url":"/claude%20code/2026/02/02/printer-mcp-server.html","date":"2026-02-02","tags":"Claude Code MCP Python 列印 PyPI"},{"title":"catime AI Prompt — 用 Gemini Flash 為每隻貓寫創意描述","url":"/ai/2026/02/02/catime-ai-prompt.html","date":"2026-02-02","tags":"AI Gemini Prompt Engineering catime Python"},{"title":"catime Gallery — 打造 kawaii 風格的貓咪展覽館","url":"/ai/2026/02/01/catime-gallery.html","date":"2026-02-01","tags":"AI GitHub Pages Frontend JavaScript catime"},{"title":"ChingTech OS:NAS 電路圖掛載與三階段非同步搜尋","url":"/chingtech%20os/2026/01/31/ctos-nas-search.html","date":"2026-01-31","tags":"ChingTech OS NAS SMB CIFS 非同步 Python 搜尋"},{"title":"ChingTech OS:Telegram Bot 完整實作","url":"/chingtech%20os/2026/01/30/ctos-telegram-bot.html","date":"2026-01-30","tags":"ChingTech OS Telegram Bot Python AI 多平台"},{"title":"catime:自動化每小時 AI 貓咪圖片生成器","url":"/ai/2026/01/30/catime-birth.html","date":"2026-01-30","tags":"AI Python GitHub Actions Gemini 圖片生成 自動化"},{"title":"ChingTech OS:多平台 Bot Adapter 重構","url":"/chingtech%20os/2026/01/29/ctos-bot-adapter.html","date":"2026-01-29","tags":"ChingTech OS 重構 設計模式 Adapter Pattern Python Line Bot Telegram"},{"title":"Telegram Bot 整合 Claude CLI + MCP 圖片生成","url":"/ai/2026/01/28/telegram-bot-claude-mcp.html","date":"2026-01-28","tags":"Telegram Bot Claude MCP Python AI Copilot SDK"},{"title":"nanobanana-py:Python 移植版 + Gemini Model Auto-Fallback","url":"/claude%20code/2026/01/28/nanobanana-py-python-port.html","date":"2026-01-28","tags":"Claude Code MCP Python Nanobanana Gemini AI"},{"title":"ChingTech OS 外部應用整合:postMessage + iframe","url":"/chingtech%20os/2026/01/27/ctos-external-app-integration.html","date":"2026-01-27","tags":"ChingTech OS postMessage iframe 整合 JavaScript Frontend"},{"title":"MD2PPT / MD2DOC 分享功能:shareToken 實作","url":"/chingtech%20os/2026/01/26/md2ppt-doc-sharetoken.html","date":"2026-01-26","tags":"ChingTech OS MD2PPT MD2DOC 分享 JavaScript Vercel"},{"title":"ChingTech OS:AI 圖片生成與記憶功能","url":"/chingtech%20os/2026/01/22/ctos-ai-image-memory.html","date":"2026-01-22","tags":"ChingTech OS AI 圖片生成 Hugging Face FLUX 記憶功能 Line Bot"},{"title":"MeterEye:AI 指示燈與警報燈偵測","url":"/computer%20vision/2026/01/20/metereye-light-detection.html","date":"2026-01-20","tags":"Computer Vision Python AI 工業自動化 MeterEye"},{"title":"ChingTech OS 多租戶架構:從設計到實作","url":"/chingtech%20os/2026/01/20/ctos-multi-tenant.html","date":"2026-01-20","tags":"ChingTech OS 多租戶 SaaS 架構設計 Python FastAPI"},{"title":"ChingTech OS:庫存管理功能開發","url":"/chingtech%20os/2026/01/16/ctos-inventory.html","date":"2026-01-16","tags":"ChingTech OS 庫存管理 廠商管理 ERP Python FastAPI"},{"title":"Nanobanana Shell 版更新:Windows 支援與 Namespace 重構","url":"/claude%20code/2026/01/15/nanobanana-shell-update.html","date":"2026-01-15","tags":"Claude Code MCP Nanobanana Shell Windows PowerShell"},{"title":"ChingTech OS:Line Bot 文件讀取功能(Word/Excel/PDF)","url":"/chingtech%20os/2026/01/15/ctos-document-reading.html","date":"2026-01-15","tags":"ChingTech OS Line Bot Python 文件處理 PDF Word Excel"},{"title":"Nanobanana:讓 Claude Code 生成圖片的 MCP Server","url":"/claude%20code/2026/01/14/nanobanana-image-generation.html","date":"2026-01-14","tags":"Claude Code MCP Nanobanana AI 圖片生成 Gemini"},{"title":"手機版 App 佈局優化實戰","url":"/chingtech%20os/2026/01/13/mobile-layout.html","date":"2026-01-13","tags":"響應式設計 CSS PWA 手機優化 ChingTech OS"},{"title":"知識庫公開分享功能實作","url":"/chingtech%20os/2026/01/12/knowledge-sharing.html","date":"2026-01-12","tags":"分享 Token FastAPI 安全性 Python ChingTech OS"},{"title":"Markdown 知識庫系統設計","url":"/chingtech%20os/2026/01/11/knowledge-base.html","date":"2026-01-11","tags":"知識庫 Markdown YAML Git Python ChingTech OS"},{"title":"專案附件與連結管理","url":"/chingtech%20os/2026/01/10/project-attachments.html","date":"2026-01-10","tags":"專案管理 MCP FastMCP NAS Python ChingTech OS"},{"title":"專案發包期程管理功能實作","url":"/chingtech%20os/2026/01/09/delivery-schedule.html","date":"2026-01-09","tags":"專案管理 MCP FastMCP Python ChingTech OS"},{"title":"內部專案管理系統:資料模型設計","url":"/chingtech%20os/2026/01/08/project-data-model.html","date":"2026-01-08","tags":"專案管理 PostgreSQL 資料庫設計 Python ChingTech OS"},{"title":"MCP 工具權限控制設計","url":"/chingtech%20os/2026/01/07/mcp-permission.html","date":"2026-01-07","tags":"MCP FastMCP 權限控制 Python ChingTech OS"},{"title":"FastMCP 實作:知識庫工具與 Scope 自動判定","url":"/chingtech%20os/2026/01/06/fastmcp-knowledge-tools.html","date":"2026-01-06","tags":"MCP FastMCP 知識庫 Python ChingTech OS"},{"title":"FastMCP 實作:專案管理工具開發","url":"/chingtech%20os/2026/01/05/fastmcp-project-tools.html","date":"2026-01-05","tags":"MCP FastMCP 專案管理 Python ChingTech OS"},{"title":"MCP 協議入門:讓 AI 使用你的工具","url":"/chingtech%20os/2026/01/04/mcp-introduction.html","date":"2026-01-04","tags":"MCP Claude AI FastMCP Python ChingTech OS"},{"title":"Line Bot 整合(五):搜尋並發送 NAS 檔案","url":"/chingtech%20os/2026/01/03/linebot-part5-nas-search.html","date":"2026-01-03","tags":"Line Bot NAS FastAPI MCP Python ChingTech OS"},{"title":"Line Bot 整合(四):群組管理與專案綁定","url":"/chingtech%20os/2026/01/02/linebot-part4-group-project.html","date":"2026-01-02","tags":"Line Bot FastAPI 專案管理 Python ChingTech OS"},{"title":"Line Bot 整合(三):與 Claude AI 對話整合","url":"/chingtech%20os/2026/01/01/linebot-part3-ai-integration.html","date":"2026-01-01","tags":"Line Bot Claude AI MCP FastAPI Python ChingTech OS"},{"title":"Line Bot 整合(二):檔案處理與 NAS 自動儲存","url":"/chingtech%20os/2025/12/31/linebot-part2-file-download.html","date":"2025-12-31","tags":"Line Bot FastAPI NAS 檔案處理 Python ChingTech OS"},{"title":"Line Bot 整合(一):Webhook 架構與訊息接收","url":"/chingtech%20os/2025/12/30/linebot-part1-webhook.html","date":"2025-12-30","tags":"Line Bot FastAPI Webhook Python ChingTech OS"},{"title":"PromptFill - 用填空的方式寫 AI Prompt","url":"/ai/%E5%B7%A5%E5%85%B7/2025/12/29/promptfill-intro.html","date":"2025-12-29","tags":"AI Prompt React 工具推薦 開源"},{"title":"用 Cloudflare Workers 免費架設短網址服務","url":"/serverless/%E6%95%99%E5%AD%B8/2025/12/29/cloudflare-workers-shorturl.html","date":"2025-12-29","tags":"Cloudflare Workers Serverless JavaScript 免費工具"},{"title":"systemd 服務配置","url":"/jaba%20ai/2025/12/25/jaba-ai-part11-systemd.html","date":"2025-12-25","tags":"Linux systemd 部署 DevOps 服務管理"},{"title":"一鍵啟動腳本設計","url":"/jaba%20ai/2025/12/25/jaba-ai-part10-deploy-script.html","date":"2025-12-25","tags":"Bash Docker 部署 DevOps 開發環境"},{"title":"菜單圖片 AI 辨識:上傳照片自動建立菜單","url":"/jaba%20ai/2025/12/24/jaba-ai-part9-menu-ocr.html","date":"2025-12-24","tags":"Python AI Claude OCR 圖片辨識 菜單管理"},{"title":"自然語言點餐:從使用者輸入到訂單建立","url":"/jaba%20ai/2025/12/24/jaba-ai-part8-natural-language.html","date":"2025-12-24","tags":"Python AI Claude 自然語言處理 LINE Bot"},{"title":"LINE 群組權限設計:從申請到審核的完整流程","url":"/jaba%20ai/2025/12/23/jaba-ai-part7-group-permission.html","date":"2025-12-23","tags":"Python LINE Bot 權限設計 狀態機"},{"title":"LINE Bot v3 SDK + FastAPI 非同步整合","url":"/jaba%20ai/2025/12/23/jaba-ai-part6-linebot-v3.html","date":"2025-12-23","tags":"Python LINE Bot FastAPI SDK v3 非同步"},{"title":"AI 日誌系統:追蹤每一次對話","url":"/jaba%20ai/2025/12/22/jaba-ai-part5-ai-logging.html","date":"2025-12-22","tags":"Python AI 日誌 可觀測性 Claude"},{"title":"Prompt Injection 防護實作","url":"/jaba%20ai/2025/12/22/jaba-ai-part4-prompt-injection.html","date":"2025-12-22","tags":"Python AI 安全 Prompt Injection Claude"},{"title":"事件隊列設計:解決 Socket.IO 與 DB Commit 順序問題","url":"/jaba%20ai/2025/12/21/jaba-ai-part3-event-queue.html","date":"2025-12-21","tags":"Python FastAPI Socket.IO 事件驅動 架構設計"},{"title":"Repository Pattern 實作:讓資料層乾淨分離","url":"/jaba%20ai/2025/12/21/jaba-ai-part2-repository.html","date":"2025-12-21","tags":"Python FastAPI SQLAlchemy Repository Pattern 架構設計"},{"title":"從 jaba + jaba-line-bot 到 jaba-ai:專案整合實戰","url":"/jaba%20ai/2025/12/20/jaba-ai-part1-integration.html","date":"2025-12-20","tags":"專案 Python FastAPI 重構 架構設計 LINE Bot"},{"title":"Jaba AI 技術分享系列:完整目錄","url":"/index/2025/12/19/jaba-ai-index.html","date":"2025-12-19","tags":"Jaba AI 目錄 系列文章 LINE Bot FastAPI Claude AI"},{"title":"pymupdf4llm - 把 PDF 轉成 AI 看得懂的 Markdown","url":"/ai/%E5%B7%A5%E5%85%B7/python/2025/12/17/pymupdf4llm-pdf-to-markdown.html","date":"2025-12-17","tags":"Python AI LLM PDF Markdown 工具推薦"},{"title":"C# WinForms 整合 Python OpenCV - Python.NET 完整教學","url":"/c%23/python/2025/12/16/csharp-pythonnet-opencv.html","date":"2025-12-16","tags":"C# Python OpenCV Python.NET WinForms 影像處理"},{"title":"uv 入門:極速 Python 套件管理","url":"/python/2025/12/13/uv-basics.html","date":"2025-12-13","tags":"Python uv 套件管理 虛擬環境"},{"title":"Linux 終端機入門:開發者必備指令","url":"/linux/2025/12/13/linux-basics.html","date":"2025-12-13","tags":"Linux Ubuntu Terminal SSH rsync"},{"title":"Git 入門:版本控制基礎指令","url":"/git/2025/12/13/git-basics.html","date":"2025-12-13","tags":"Git 版本控制 GitHub"},{"title":"Docker 基礎概念與常用指令","url":"/devops/2025/12/13/docker-basics.html","date":"2025-12-13","tags":"Docker Docker Compose 容器化 DevOps"},{"title":"Docker Compose 一鍵啟動開發環境","url":"/devops/2025/12/13/devops-part2-docker.html","date":"2025-12-13","tags":"Docker Docker Compose PostgreSQL DevOps"},{"title":"Alembic 資料庫版本控制:讓 Schema 變更可追蹤","url":"/devops/2025/12/13/devops-part1-alembic.html","date":"2025-12-13","tags":"Python Alembic PostgreSQL Migration"},{"title":"ChingTech OS 技術分享系列:完整目錄","url":"/index/2025/12/13/ching-tech-os-index.html","date":"2025-12-13","tags":"ChingTech OS 目錄 系列文章"},{"title":"檔案管理 API:FastAPI 實作上傳下載刪除","url":"/smb/nas/2025/12/12/smb-nas-part2-api.html","date":"2025-12-12","tags":"FastAPI REST API 檔案管理 Python NAS"},{"title":"SMB 協定入門:用 Python 連接公司 NAS","url":"/smb/nas/2025/12/12/smb-nas-part1-protocol.html","date":"2025-12-12","tags":"Python SMB NAS smbprotocol Synology"},{"title":"登入追蹤:裝置指紋與地理位置記錄","url":"/security/2025/12/12/security-part2-tracking.html","date":"2025-12-12","tags":"安全 GeoIP 指紋 JavaScript Python"},{"title":"認證系統:用 NAS 帳號實現 SSO 效果","url":"/security/2025/12/12/security-part1-auth.html","date":"2025-12-12","tags":"安全 認證 Session FastAPI Python"},{"title":"前端整合:xterm.js 打造完整終端體驗","url":"/web%20terminal/2025/12/11/web-terminal-part3-xtermjs.html","date":"2025-12-11","tags":"JavaScript xterm.js Terminal 前端 Socket.IO"},{"title":"後端架構:FastAPI + Socket.IO 雙向通訊","url":"/web%20terminal/2025/12/11/web-terminal-part2-socketio.html","date":"2025-12-11","tags":"FastAPI Socket.IO WebSocket Python 即時通訊"},{"title":"什麼是 PTY?讓網頁跑出真正的 Terminal","url":"/backend/2025/12/11/web-terminal-part1-pty.html","date":"2025-12-11","tags":"Python PTY Terminal Linux"},{"title":"System Prompt 設計:打造專屬 AI 助手人格","url":"/claude%20ai/2025/12/11/claude-ai-part3-prompt.html","date":"2025-12-11","tags":"AI Claude Prompt Engineering System Prompt"},{"title":"Token 管理:估算、警告與自動壓縮","url":"/claude%20ai/2025/12/11/claude-ai-part2-token.html","date":"2025-12-11","tags":"AI Claude Token 對話壓縮 JavaScript"},{"title":"架構選擇:Claude CLI 整合與對話設計","url":"/claude%20ai/2025/12/11/claude-ai-part1-architecture.html","date":"2025-12-11","tags":"AI Claude Python asyncio 對話系統"},{"title":"視窗系統(下):Window Snap 與 Taskbar 整合","url":"/frontend/2025/12/10/window-system-part3-snap.html","date":"2025-12-10","tags":"JavaScript UX 視窗系統 Window Snap"},{"title":"視窗系統(中):縮放、最大化與多視窗管理","url":"/frontend/2025/12/10/window-system-part2-resize.html","date":"2025-12-10","tags":"JavaScript DOM 視窗系統 縮放"},{"title":"視窗系統(上):讓網頁變成桌面 - 基礎拖曳功能","url":"/frontend/2025/12/10/window-system-part1-drag.html","date":"2025-12-10","tags":"JavaScript DOM 視窗系統 拖曳"},{"title":"為什麼我們選擇不用 React/Vue?談 Vanilla JS 的適用場景","url":"/frontend/2025/12/10/vanilla-js-why-no-framework.html","date":"2025-12-10","tags":"JavaScript IIFE 前端架構 Vanilla JS"},{"title":"CSS 設計系統:一行程式碼切換全站主題","url":"/frontend/2025/12/10/css-design-system-theme.html","date":"2025-12-10","tags":"CSS 設計系統 主題切換 CSS Variables"},{"title":"Certbot SSL 憑證完整教學 - Let's Encrypt 免費 HTTPS","url":"/devops/2025/12/10/certbot-ssl-guide.html","date":"2025-12-10","tags":"教學 SSL HTTPS Certbot Let's Encrypt Nginx Docker 資安"},{"title":"Render 免費部署教學 - 以 LINE Bot 為例","url":"/devops/2025/12/09/render-deploy-guide.html","date":"2025-12-09","tags":"教學 部署 Render Python Flask LINE Bot PaaS"},{"title":"LINE Bot 開發入門 - 以呷爸點餐系統為例","url":"/line%20bot/2025/12/09/line-bot-guide.html","date":"2025-12-09","tags":"教學 LINE Bot Python Flask Messaging API Webhook"},{"title":"Jaba LINE Bot - 讓點餐對話進入 LINE","url":"/line%20bot/2025/12/09/jaba-line-bot.html","date":"2025-12-09","tags":"專案 Python Flask LINE Bot API Claude Code SDD"},{"title":"SDD 規格驅動開發入門(二):指令介紹篇","url":"/sdd/2025/12/08/sdd-commands-guide.html","date":"2025-12-08","tags":"教學 AI Claude Code SDD OpenSpec"},{"title":"呷爸 jaba - 透過 LINE 群組輕鬆訂餐","url":"/projects/2025/12/08/jaba.html","date":"2025-12-08","tags":"專案 Python FastAPI AI Web LINE Bot Claude Code SDD"},{"title":"SDD 規格驅動開發入門(一):環境安裝篇","url":"/sdd/2025/12/07/sdd-setup-guide.html","date":"2025-12-07","tags":"教學 Python FastAPI AI Claude Code SDD"},{"title":"RosAGV - 企業級 AGV 車隊管理系統","url":"/%E5%B7%A5%E6%A5%AD%E8%87%AA%E5%8B%95%E5%8C%96/ros2/agv/2025/12/05/rosagv-fleet-management-system.html","date":"2025-12-05","tags":"ROS2 AGV Docker Zenoh 車隊管理 工業自動化"},{"title":"擎添工業官方網站","url":"/projects/2025/12/05/ching-tech-website.html","date":"2025-12-05","tags":"專案 Python FastAPI Web Robot AGV AI Claude Code SDD"},{"title":"Fish Fry Counter 魚苗計數系統","url":"/projects/2025/11/27/fish-cv.html","date":"2025-11-27","tags":"專案 Python FastAPI OpenCV YOLO AI Claude Code SDD"},{"title":"ROS2 基礎概念入門","url":"/ros2/2025/11/24/ros2-basics.html","date":"2025-11-24","tags":"ROS2 Jazzy 機器人 AGV"},{"title":"WebAGV - AGV 車隊即時監控看板","url":"/web%E9%96%8B%E7%99%BC/agv/%E5%8D%B3%E6%99%82%E7%9B%A3%E6%8E%A7/2025/04/24/webagv-monitoring-dashboard.html","date":"2025-04-24","tags":"Vue3 Node.js Socket.IO Leaflet MQTT AGV 即時監控"},{"title":"AnalyzerUI","url":"/projects/2025/01/08/AnalyzerUI.html","date":"2025-01-08","tags":"產品 C#"},{"title":"CTCUI SMD 全自動智慧檢測系統:WiseTechVision 在 QC 自動化的應用","url":"/computer%20vision/kuka/automation/2023/06/07/ctcui-smd-aoi-system.html","date":"2023-06-07","tags":"WiseTechVision KUKA AOI 品質檢測 自動化 SMD"},{"title":"國立工藝中心 手臂雕刻系統","url":"/2021/06/28/ntcri.html","date":"2021-06-28","tags":"專案 Robot Unity"},{"title":"QRCodeScanner 1922實聯制QRCode掃瞄器","url":"/2021/05/20/QRCodeScanner.html","date":"2021-05-20","tags":"專案 Unity Android"},{"title":"亞洲大學 2020 - KUKA 工業機器手臂 3D 動畫模擬與操作","url":"/%E6%95%99%E5%AD%B8/robotsim/kuka/2020/11/11/asia2020-RobotSim.html","date":"2020-11-11","tags":"教學 Unity Robot RobotSim KUKA"},{"title":"亞洲大學 2020 - KUKA 機器手臂與 Leap Motion 手勢控制","url":"/%E6%95%99%E5%AD%B8/robotsim/kuka/leapmotion/2020/11/11/asia2020-RobotLeapMotion.html","date":"2020-11-11","tags":"教學 Unity Robot LeapMotion KUKA EKI RSI"},{"title":"WiseTechVision 視覺系統整合應用:散亂螺絲自動整列","url":"/computer%20vision/kuka/2020/07/20/wisetech-vision-screw-sorting.html","date":"2020-07-20","tags":"WiseTechVision KUKA 機器視覺 自動化 工業視覺"},{"title":"KUKA 力覺感知應用:Tray 盤取放堆疊自動化","url":"/kuka/automation/2020/06/18/kuka-force-sensing-tray-stack.html","date":"2020-06-18","tags":"KUKA 力覺感知 Force Sensing Tray盤 堆疊自動化"},{"title":"KUKA 力覺感知應用:PCB 來料深度感測與精確吸取","url":"/kuka/automation/2020/06/05/kuka-force-sensing-pcb-depth.html","date":"2020-06-05","tags":"KUKA 力覺感知 Force Sensing PCB 自動化"},{"title":"實踐大學 2019 - 機器手臂程式設計:從模擬到實機","url":"/%E6%95%99%E5%AD%B8/robotsim/kuka/2019/03/13/usc2019-RobotSim.html","date":"2019-03-13","tags":"教學 Unity Robot RobotSim KUKA KRL"},{"title":"嘉南藥理大學 2018 - Unity 互動科技:RobotSim 機器手臂模擬","url":"/%E6%95%99%E5%AD%B8/robotsim/2018/04/16/cnu2018-RobotSim.html","date":"2018-04-16","tags":"教學 Unity Robot RobotSim 互動科技"},{"title":"RobotSim:Unity 3D 機器手臂模擬系統","url":"/kuka/robotsim/2018/03/01/robotsim-unity-robot-simulation.html","date":"2018-03-01","tags":"RobotSim Unity 機器手臂模擬 KUKA 運動學"},{"title":"KUKA 機器手臂力覺感知技術:不外掛 Sensor 的扭力檢測應用","url":"/kuka/automation/2017/08/09/kuka-force-sensing-without-sensor.html","date":"2017-08-09","tags":"KUKA 力覺感知 Force Sensing KRL 自動化"},{"title":"KUKA 力覺感知應用:記憶卡插件力道感測與反向錯放偵測","url":"/kuka/automation/2017/08/09/kuka-force-sensing-memory-card.html","date":"2017-08-09","tags":"KUKA 力覺感知 Force Sensing 插件組裝 品質檢測"},{"title":"實踐大學 2017 - 聯網感測實作","url":"/%E6%95%99%E5%AD%B8/iot/arduino/2017/06/19/usc2017nsp.html","date":"2017-06-19","tags":"教學 Arduino IoT MQTT MySQL"},{"title":"嘉南藥理大學 2017 - Unity 程式設計基本課程","url":"/%E6%95%99%E5%AD%B8/unity/%E9%81%8A%E6%88%B2%E9%96%8B%E7%99%BC/2017/04/24/cnu2017.html","date":"2017-04-24","tags":"教學 Unity C# Networking"},{"title":"五花果的後花園 - 讓小朋友的畫作在大螢幕中活起來","url":"/%E5%B0%88%E6%A1%88/unity/%E4%BA%92%E5%8B%95%E8%97%9D%E8%A1%93/2017/01/14/8boo-land-5flowergod.html","date":"2017-01-14","tags":"專案 Unity 互動藝術 影像處理"},{"title":"嘉南藥理大學 2016 - 互動應用","url":"/%E6%95%99%E5%AD%B8/unity/%E4%BA%92%E5%8B%95%E6%87%89%E7%94%A8/2016/09/21/cnu2016.html","date":"2016-09-21","tags":"教學 Unity AR Kinect LeapMotion"},{"title":"實踐大學 2016 人機互動課程專案 - 雲端相簿 (Web Server 端)","url":"/%E5%B0%88%E6%A1%88/web/backend/2016/03/26/usc2016hci_CloudAlbum.html","date":"2016-03-26","tags":"教學 Web PHP MySQL"},{"title":"實踐大學 2016 人機互動課程專案 - AR 相機 (APP Client 端)","url":"/%E5%B0%88%E6%A1%88/unity/ar/2016/03/26/usc2016hci_ARCamera.html","date":"2016-03-26","tags":"教學 Unity Android AR Vuforia NGUI"},{"title":"實踐大學 2016 - 人機互動技術與應用","url":"/%E6%95%99%E5%AD%B8/unity/hci/2016/02/14/usc2016hci.html","date":"2016-02-14","tags":"教學 Unity AR Kinect LeapMotion Vuforia"},{"title":"實踐大學 2015 - 創意互動導覽行動平台人才培育學程","url":"/%E6%95%99%E5%AD%B8/unity/android/2015/11/26/usc2015.html","date":"2015-11-26","tags":"教學 Android Unity AR Vuforia"},{"title":"艾思摩爾手作坊iCEMORE - 單頁式","url":"/2015/11/12/icemore2.html","date":"2015-11-12","tags":"專案 Web"},{"title":"艾思摩爾手作坊iCEMORE","url":"/2015/11/03/icemore.html","date":"2015-11-03","tags":"專案 Web"},{"title":"打火解油出任務 - Unity + Kinect 大型活動體感遊戲","url":"/%E5%B0%88%E6%A1%88/unity/%E4%BA%92%E5%8B%95%E9%81%8A%E6%88%B2/2015/08/20/kinect-game-dagfire.html","date":"2015-08-20","tags":"專案 Unity Kinect 互動遊戲"},{"title":"無人飛行船地面站即時監控系統","url":"/%E5%B0%88%E6%A1%88/%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%B3%BB%E7%B5%B1/%E5%8D%B3%E6%99%82%E7%9B%A3%E6%8E%A7/2015/06/01/airship-ground-station.html","date":"2015-06-01","tags":"專案 Microchip 嵌入式系統 Flash ActionScript GPRS 即時監控"},{"title":"無人飛行船自動導航系統","url":"/%E8%AB%96%E6%96%87/%E5%B5%8C%E5%85%A5%E5%BC%8F%E7%B3%BB%E7%B5%B1/%E8%87%AA%E5%8B%95%E5%B0%8E%E8%88%AA/2011/06/01/airship-auto-navigation-thesis.html","date":"2011-06-01","tags":"論文 Microchip 嵌入式系統 GPS GPRS 自動導航 飛行控制"}]
// assets/js/blog-search.js
(async function () {
  const input = document.getElementById('blog-search');
  const list = document.getElementById('post-list');
  const out = document.getElementById('search-results');
  const pagination = document.querySelector('.pagination');
  let idx = null;
  input.addEventListener('input', async function () {
    const q = input.value.trim().toLowerCase();
    if (!q) { out.hidden = true; list.hidden = false; pagination.hidden = false; return; }
    if (!idx) idx = await (await fetch('/search.json')).json();
    const hits = idx.filter(p => (p.title + ' ' + p.tags).toLowerCase().includes(q)).slice(0, 30);
    out.innerHTML = hits.map(p =>
      `<li><h2><a href="${p.url}">${p.title}</a></h2><p class="meta">${p.date}</p></li>`
    ).join('') || '<li><p class="meta">沒有符合的文章。</p></li>';
    out.hidden = false; list.hidden = true; pagination.hidden = true;
  });
})();
curl -s http://localhost:4400/blog/ | grep -c "post-list"
curl -s http://localhost:4400/blog/page2/ | grep -c "post-list"
curl -s http://localhost:4400/search.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d))"

Expected: 兩頁都有列表、search.json 有 205 筆。瀏覽器開 /blog/ 打「台語」確認即時搜尋出現該篇。tags 頁 curl -s http://localhost:4400/tags/ | grep -c tag 仍正常(它用 layout: page,Task 2 已覆蓋)。

git add -A && git commit -m "feat(blog): /blog 分頁列表+客戶端搜尋,tags 頁沿用新版型

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"

Task 5: 作品牆截圖素材

Files:

Interfaces:

for u in https://yazelin.github.io/ai-chant-magic/ https://yazelin.github.io/k-rider/ https://yazelin.github.io/roll-formosa/ https://yazelin.github.io/mandarin-taigi/ https://yazelin.github.io/mori-sprite-studio/; do curl -s -o /dev/null -w "%{http_code} $u\n" $u; done

CTOS/魚苗/呷爸沒有公開網頁——這三個用 blog 文章內既有的 GitHub Releases 圖(找該篇文章第一張圖的 URL 下載轉 webp),不截圖。

// scripts/portfolio-shots.mjs
import { chromium } from 'playwright';
const shots = [
  ['ai-chant-magic', 'https://yazelin.github.io/ai-chant-magic/'],
  ['k-rider', 'https://yazelin.github.io/k-rider/'],
  ['roll-formosa', 'https://yazelin.github.io/roll-formosa/'],
  ['taigi', 'https://yazelin.github.io/mandarin-taigi/'],
  ['sprite-studio', 'https://yazelin.github.io/mori-sprite-studio/'],
];
const b = await chromium.launch({ channel: 'chrome' });
const page = await b.newPage({ viewport: { width: 1280, height: 800 } });
for (const [name, url] of shots) {
  await page.goto(url, { waitUntil: 'networkidle' });
  await page.waitForTimeout(2500); // 等動畫/canvas 進場
  await page.screenshot({ path: `images/portfolio/${name}.png` });
  console.log(name, 'done');
}
await b.close();
cd /home/ct/yazelin.github.io && mkdir -p images/portfolio && node scripts/portfolio-shots.mjs
python3 - <<'EOF'
from PIL import Image; import glob, os
for f in glob.glob('images/portfolio/*.png'):
    Image.open(f).convert('RGB').save(f[:-4]+'.webp', quality=82, method=6); os.remove(f)
    print(f, os.path.getsize(f[:-4]+'.webp')//1024, 'KB')
EOF

Expected: 每張 <150KB;超過就降 quality 到 75 重轉。人工看一眼每張圖不是空白/載入中畫面(canvas 類站要真的有畫面)。

git add images/portfolio scripts/portfolio-shots.mjs && git commit -m "assets: 作品牆截圖(webp)+截圖腳本

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"

Task 6: 首頁 landing(文案全部標草稿)

Files:

Interfaces:

從甲方思維/AI 發包相關文章挑 4–6 篇(用 grep -l "甲方思維" _posts/*.md 起手,加上咏唱魔法 index、台語辭典篇),front matter 加:

featured: true
featured-why: "為什麼值得讀的一句話"
---
layout: default
title: null
share-description: 林亞澤 Yaze — 甲方思維:不寫程式也能把軟體做出來。工業自動化 10+ 年轉 AI 應用,一個人 + AI 維護 30+ 個活躍專案。
head-extra:
  - head-custom.html
---
<!-- 文案草稿:全部待 yazelin 逐句核可 -->
<section class="hero">
  <h1>不寫程式,也能把軟體做出來</h1>
  <p class="sub">我用「甲方思維」驅動 AI 開發:開規格、下發包、做驗收。工業自動化 10+ 年,現在一個人 + AI 同時維護 30+ 個上線專案——這個網站會教你同一套方法。</p>
  <div class="signup">
  <h2>保持聯絡</h2>
  <p class="section-lead">留個 email,有新文章或新作品上線時告訴你。</p>
  <form data-signup data-source="blog">
    <input type="email" name="email" placeholder="you@example.com" aria-label="Email" required>
    <input type="text" name="company" class="hp" tabindex="-1" autocomplete="off" aria-hidden="true">
    <button type="submit">訂閱</button>
  </form>
  <p class="msg" aria-live="polite"></p>
</div>
<script>
document.querySelectorAll('form[data-signup]').forEach(function (f) {
  if (f.dataset.bound) return; f.dataset.bound = '1';
  f.addEventListener('submit', async function (e) {
    e.preventDefault();
    var msg = f.parentElement.querySelector('.msg');
    msg.textContent = '送出中…';
    try {
      var r = await fetch('https://k-rider-api.yazelinj303.workers.dev/signup', {
        method: 'POST', headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ email: f.email.value, company: f.company.value, source: f.dataset.source })
      });
      var d = await r.json();
      msg.textContent = d.ok ? (d.already ? '這個 email 已經訂閱過了。' : '訂閱成功,之後見。') : '出了點問題,再試一次。';
      if (d.ok && !d.already) f.reset();
    } catch (err) { msg.textContent = '網路怪怪的,稍後再試。'; }
  });
});
</script>

</section>

<section class="section container-wide" id="work">
  <h2 class="section-title">上線的作品,不是 demo</h2>
  <p class="section-lead">每一個都可以點進去用。這是「AI 發包法」的產出證明。</p>
  <div class="work-grid">
    <a class="work-card" href="https://yazelin.github.io/ai-chant-magic/">
      <img src="https://cdn.jsdelivr.net/gh/yazelin/yazelin.github.io@master/images/portfolio/ai-chant-magic.webp" alt="真AI咏唱魔法" loading="lazy">
      <div class="body"><h3>真AI咏唱魔法</h3><p>對麥克風唸咒語,AI 即時生成魔法效果的生存遊戲。</p></div>
    </a>
    <!-- 其餘 7 張卡片同構:ctos / k-rider / roll-formosa / taigi / sprite-studio / fish-cv / jaba,
         標題與一句話說明照下表,連結:有站連站、沒站連 blog 該篇文章 -->
  </div>
</section>

<section class="section container-wide">
  <div class="story">
    <h2 class="section-title">從工廠到 AI</h2>
    <p>我在工業自動化做了十幾年:機器人、視覺檢測、AGV 車隊。工業現場預算有限,習慣了用軟體取代昂貴的感測器、用不一樣的解法把事情做成。</p>
    <p>2024 年起我把同一套「發包給供應商」的功夫,原封不動用在 AI 身上——結果是一個人維護 30+ 個活躍專案。這套方法不需要你會寫程式,需要你會當一個好甲方。</p>
    <p style="text-align:center"><a href="/about/">完整的故事 →</a></p>
  </div>
</section>

<section class="section container">
  <h2 class="section-title">從這幾篇開始讀</h2>
  <ul class="featured-list">
    
    
    <li><a href="/ai/2026/07/15/taigi-hakka-dictionaries.html">「長頸鹿怎麼沒有?」兩天長出兩本離線辭典</a><p class="why">願望池裡的一句話,兩天長成兩本教育部等級的離線辭典。</p></li>
    
    <li><a href="/ai/2026/07/09/kb-driven-dev-flow.html">這個 demo 裡 AI 一行新程式都沒寫,但我覺得它比寫程式的 demo 更值得看</a><p class="why">AI 一行新程式都沒寫的 demo,規格放知識庫、AI 自己接單自己回報。</p></li>
    
    <li><a href="/index/2026/07/06/ai-chant-magic-index.html">真。AI。咏唱魔法 系列:完整目錄</a><p class="why">一款對著麥克風唸咒語的網頁生存遊戲,系列文章總入口。</p></li>
    
    <li><a href="/ai/%E9%96%8B%E7%99%BC%E5%B7%A5%E5%85%B7/2026/06/19/ai-overnight-loop.html">我睡覺,它整晚加城市 —— 怎麼排班讓 AI 自己做完一整夜的內容</a><p class="why">睡一覺起來 AI 自己跑完一整夜,怎麼排班讓它整晚不用人顧。</p></li>
    
    <li><a href="/ai/2026/06/16/k-rider-case-study.html">從一個點子到一個會動的股價遊戲:我怎麼用「甲方思維」發包給 AI</a><p class="why">「甲方思維」怎麼把一個點子發包給 AI,做成真的上線的股價遊戲。</p></li>
    
  </ul>
  <p style="text-align:center"><a href="/blog/">全部 207 篇文章 →</a></p>
</section>

<section class="section container"><div class="signup">
  <h2>保持聯絡</h2>
  <p class="section-lead">留個 email,有新文章或新作品上線時告訴你。</p>
  <form data-signup data-source="blog">
    <input type="email" name="email" placeholder="you@example.com" aria-label="Email" required>
    <input type="text" name="company" class="hp" tabindex="-1" autocomplete="off" aria-hidden="true">
    <button type="submit">訂閱</button>
  </form>
  <p class="msg" aria-live="polite"></p>
</div>
<script>
document.querySelectorAll('form[data-signup]').forEach(function (f) {
  if (f.dataset.bound) return; f.dataset.bound = '1';
  f.addEventListener('submit', async function (e) {
    e.preventDefault();
    var msg = f.parentElement.querySelector('.msg');
    msg.textContent = '送出中…';
    try {
      var r = await fetch('https://k-rider-api.yazelinj303.workers.dev/signup', {
        method: 'POST', headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ email: f.email.value, company: f.company.value, source: f.dataset.source })
      });
      var d = await r.json();
      msg.textContent = d.ok ? (d.already ? '這個 email 已經訂閱過了。' : '訂閱成功,之後見。') : '出了點問題,再試一次。';
      if (d.ok && !d.already) f.reset();
    } catch (err) { msg.textContent = '網路怪怪的,稍後再試。'; }
  });
});
</script>
</section>

作品卡片文字(草稿,一併待核可):

name 標題 一句話 連結
ai-chant-magic 真AI咏唱魔法 對麥克風唸咒語,AI 即時判定的生存遊戲
ctos ChingTech OS 中小製造業的 AI 企業系統,商用中 blog 文
k-rider K-Rider K線騎手 用真實股價 K 線玩的騎乘遊戲
roll-formosa Roll Formosa 把台灣街景滾成一顆球的遊戲
taigi 台語/客語辭典 兩天長出兩本教育部資料離線辭典
sprite-studio Mori Sprite Studio 一張圖生成完整角色動畫包的工具
fish-cv 魚苗計數系統 用視覺 AI 數魚苗,取代人工點數 blog 文
jaba 呷爸 Jaba 公司訂便當 LINE Bot,天天在用 blog 文

瀏覽器開 http://localhost:4400/ :四屏都渲染、8 張卡片圖有出來、精選文章列表非空、兩個訂閱表單都能打 API(打一筆測試 email 後從 D1 刪除)。iPhone 13 viewport(Playwright devices['iPhone 13'] + channel:'chrome' + .tap())確認不破版。

git add -A && git commit -m "feat(landing): 首頁改個人品牌 landing(文案草稿待核可)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"

Task 7: 文案核可關卡(HARD GATE:需 yazelin 逐句拍板)

Files:

定位句、副標、三個 section 標題與 lead、8 張卡片的標題+一句話、故事兩段、訂閱表單文案、精選文章的 featured-why。逐句列出,等回覆。沒核可不得進 Task 8。

grep -rn "接住" index.html _includes/ && echo "FAIL: 禁用詞" || echo OK
git add -A && git commit -m "copy: 首頁文案定稿(yazelin 核可)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"

Task 8: 驗收與上線(merge 前全部過)

Files:

# 線上抓 10 個現行 URL(含 2011 最舊與 2026 最新), 本機同 path 必須 200
for p in $(curl -s https://yazelin.github.io/sitemap.xml | grep -o '<loc>[^<]*' | sed 's/<loc>//;s|https://yazelin.github.io||' | shuf -n 10); do
  curl -s -o /dev/null -w "%{http_code} $p\n" "http://localhost:4400$p"; done

Expected: 全部 200(landing 換掉的舊首頁分頁 /page2 等除外——那些由 /blog/page2/ 取代,301 無法做,GitHub Pages 不支援,可接受:舊分頁 URL 本來就不該被外部引用;sitemap 會更新)。

curl -s http://localhost:4400/feed.xml | head -5          # RSS
curl -s http://localhost:4400/sitemap.xml | grep -c "<loc>"  # sitemap
curl -s http://localhost:4400/tags/ | grep -c "tag"          # tags
curl -s http://localhost:4400/404.html | grep -c "找不到"     # 404

Playwright iPhone 13 走首頁四屏截圖人工看;mcp chrome-devtools lighthouse_audit 對本機首頁,performance 分數記錄下來(基準:不低於改版前線上首頁——先對線上跑一次留數字)。

本機或 push 後線上開任一篇文章,giscus iframe 有載入(giscus 認 pathname,本機 localhost 不一定能載——線上驗)。

git checkout master && git merge --no-ff rebrand -m "feat: 個人品牌主站改版上線

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>" && git push
# 等 Pages 部署後:
for p in / /blog/ /about/ /tags/ /ai/2026/07/15/taigi-hakka-dictionaries.html; do
  curl -s -o /dev/null -w "%{http_code} $p\n" "https://yazelin.github.io$p"; done

Expected: 全 200;線上再開首頁確認訂閱表單真的寫進 D1(打一筆再刪)。giscus 線上驗。README 若描述舊主題,一併更新。


Task 9(後續、不擋上線): About 轉型敘事重寫

Self-Review 紀錄