# 建站

> 依照 spec 生出一頁式網站，包含會流動的首屏

- Skill: `yazelin/skill` (Agent Skill)
- Install (CLI): `npx skillmds@latest add yazelin/skill`
- Raw SKILL.md: https://api.skillmd.com/api/skills/yazelin/skill/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: yazelin (https://skillmd.com/u/yazelin)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/yazelin/skill

---


# 階段三：建站

## 動手之前先唸一次 avoid

`spec/site.yaml` 的 `avoid` 是使用者明講「絕對不要」的東西，抄的是他的原話。
**排版之前唸一次，交出去之前再唸一次。**

這一項很容易被忽略，因為它講的是「不要做什麼」，不會主動跳出來提醒你。
實測的例子：「不要像購物網站那樣一格一格標價錢放購物車」——
那句話直接否決掉用卡片格排服務項目的做法，要改用條列。

## 先確認族，再談版面

`docs/families.md` 有七族：克制、訊號、圖鑑、霓虹街機、終端、粗獷、復古介面。
**族是性格，概念是骨架，兩件事分開。** 同一個概念可以做成不同族：
「工單」可以是克制的工程圖，也可以是粗獷的黑黃警示牌。

`templates/` 裡的骨架目前只覆蓋兩族（克制與訊號）。
**其餘五族沒有現成骨架，要照那一份的「關鍵手法」自己寫**，
每一族都附了色彩配方、動畫的性格、三到五個 CSS 層級的手法與參考站。

**族不對就整個重來，不要在錯的族裡調參數。**
一個做電音的人配上克制族，字距與留白調到死都不會對。

## 概念夠強的時候，不要挑版面，用概念生一個

`templates/` 那五種是**沒有概念時的安全牌**。訪談問出了概念，
就照 `docs/concept.md` 的三個問題生一個新的：

1. **容器**：每個區塊被裝在什麼裡面（一片面板、一張圖紙、一格片格、一列欄位）
2. **重複單元**：內容清單怎麼排（一台設備、一個件號、一格底片、一次會談）
3. **分節**：區塊之間怎麼編號（U 數、圖號、底片編號、第幾次）

`examples/` 裡那四個都是這樣生出來的，**沒有一個屬於那五種版面**：

| 範例 | 容器 | 重複單元 | 分節 |
|---|---|---|---|
| 講師 | 一張圖紙加右下角標題欄 | 件號 M-01 | 圖號 DWG-01…05 |
| 後端 | 一片 U 面板加一顆綠燈 | 一台設備 | U01…U05 |
| 攝影 | 一格片格加邊碼 | 一格底片 230-014 | FRAME 036A…060 |
| 諮商 | 一列「標籤｜內容」欄位 | 一次會談 | 單號 0001…0005 |

**這條路的成本沒有比較高**，四份都是純 CSS，加起來不到兩百行版面樣式。
真正的成本在訪談有沒有問出概念。

生出來的東西要跟五種版面一樣通過 `tools/check.mjs`，
而且 `docs/craft.md` 那三條（破除置中、中文行高、標題不要負字距）一樣要遵守。

## 沒有概念的時候才挑版面

`templates/` 裡有六種版面，**結構不一樣，不只是換顏色**。
開 `templates/preview.html` 可以一次看到，每一種都寫了適合誰。

| 版面 | 檔案 | 給誰 |
|---|---|---|
| 堆疊 | `stack.html` | 內容量中等到大。判斷不出來就用這個 |
| 左右分屏 | `split.html` | 內容量中等、想要一點設計感。區塊超過六個就改用堆疊 |
| 編號索引 | `editorial.html` | **內容少的人用這個最划算**，它靠結構撐場面不靠字數 |
| 滿版出血 | `bleed.html` | **手上有好圖的人**。沒有圖不要選 |
| 工控面板 | `console.html` | 製造業、自動化、工業軟體。**這是概念驅動的示範，不是通用版面** |
| 訊號 | `signal.html` | **動效當主角那一路。** 作品是視覺的人、想被記住勝過被讀完的人 |

版面決定於**內容有多少**與**有沒有圖**，不是決定於好不好看。
訪談的時候他能講出來的東西有多少，這裡就會知道。

`console.html` 是特例：它是照一個概念（工廠的控制台）做出來的示範。
**使用者不在那一行就不要拿來用。** 要看的是它怎麼把一個概念變成版面。
實測它跟同樣內容的中性版對打是五比零，做法在 `docs/concept.md`。

挑好或生好之後開工：

```bash
mkdir -p site
cp templates/<挑的版面>.html site/index.html
cp templates/tokens.css templates/base.css site/
cp hero/<挑的動效>.js site/hero.js
```

不要直接改 `templates/`。使用者之後想重來一次，模板要是乾淨的。

## 模板是骨架，不是成品

每一份版面裡填的都是示範內容，有一個叫李默的虛構人物。
那些字全部都要換掉。頁首那一行 `<meta name="x-demo-content" content="yes">`
換完之後刪掉，`tools/check.mjs` 看到那一行就直接判不通過。

**區塊可以刪。** 模板大致有這些區塊：首屏、我是誰、可以找我做什麼、做過的事、
常見問題、行動呼籲、頁尾。使用者沒東西可以填的區塊就整塊刪掉，
不要留一個只有兩行字的區塊在那裡。求職的人通常不需要「可以找我做什麼」，
名片型的人只需要首屏加頁尾。

## 選風格

`tokens.css` 裡有四組預設，寫在 `<html data-vibe="...">`：

| 風格 | 長什麼樣 | 給誰 |
|---|---|---|
| `calm` 克制 | 淺底、細字、大量留白、幾乎沒有顏色 | 求職、顧問、專業服務 |
| `bold` 明確 | 深底、大字、一個亮色 | 賣東西、接案 |
| `gallery` 作品優先 | 介面退到最淡，圖片佔滿 | 設計、攝影、影像 |
| `grand` 大氣 | 墨底、襯線大標、金屬色、超大留白 | 講者、顧問、想要沉穩恢弘那一路 |

預覽的時候網址加 `?vibe=grand` 就能直接換一種看。定案之後把
`<html data-vibe>` 寫死，並且刪掉檔尾那段讀網址參數的程式。

**四組都只是起點。** 使用者有自己的品牌色就覆蓋 `--accent`；
字太大就調 `--step-4`；留白不夠就加 `--space-6`。
顏色、字級、間距這些都在 `tokens.css` 改。版面本身的樣式在各份 `.html` 自己的
`<style>` 裡，共用的元件在 `base.css`。**不要為了改一個顏色去動 `base.css`。**

## 首屏動效

五支效果放在 `hero/`，開 `hero/preview.html` 可以一次看到五種在動。
把選中的那一支複製成 `site/hero.js`，然後改 `index.html` 檔尾的 `HERO.fx`。

| 效果 | 函式名 | 個性 | 配哪個風格 |
|---|---|---|---|
| 流體漸層 | `flowGradient` | 色塊疊加後模糊，緩慢流動。最省效能，也最搶眼 | `bold` |
| 粒子場 | `particleField` | 點漂移並連線，滑鼠會推開。技術感重 | `bold`、`gallery` |
| 噪聲線條 | `noiseLines` | 一疊橫線緩緩起伏，像等高線。最安靜 | `calm` |
| 幾何緩動 | `geoDrift` | 大型線稿圖形極慢地漂移，像會呼吸的海報 | `grand`、`gallery` |
| 流體墨彩 | `fluidInk` | 游標攪動、點擊潑灑的流體，沒人動的時候自己流 | `grand`、`bold` |

**流體墨彩是唯一的例外。** 它是移植過來的 Navier-Stokes 求解器
（出處在 `THIRD_PARTY_NOTICES.md`），四百多行，裡面的 shader 不用讀，
調 `colors`、`intensity`、`dissipation`、`idle`、`quality` 這五個參數就好。
它最有存在感，也最吃效能：**首屏文字多的時候不要用它**，
低階手機記得傳 `quality: 'low'`。

**另外四支是起手式，不是成品。**
每一支的參數都開在檔案最上面。照使用者的內容調過再交出去：

- 首屏字多的人，把動效的對比與密度往下壓，不要跟標題搶。
- 首屏只有一句話的人，可以放大幅度與速度，讓畫面自己有事情在發生。
- 品牌色只有一個的人，用單色版本，不要硬湊三色漸層。
- 內容偏嚴肅的人，速度一律減半。

**上面這幾條是「動效當背景」那一路的分寸，不是全部的路。**
原本這裡只寫了這一路，結果做出來的東西全部是同一種美學：
單色、克制、文件感。那是一種品味，不是唯一一種。

**還有另一路：動效當主角。** 這一路的做法在下一節。

## 另一路：動效當主角

`templates/signal.html` 是這一路的示範。它把上面那幾條倒過來：
動效鋪滿整個首屏、名字用 `background-clip: text` 剪成看動效的窗、
顆粒與暗角疊上去、捲離首屏才淡出。

**適合誰：** 作品本身就是視覺的人、想被記住勝過想被讀完的人、
名字比職稱更重要的人。
**不適合誰：** 內容量大、要被仔細讀的人。那種人用前面五種。

這一路可以重複使用的幾招，全部是純 CSS：

```css
/* 一、名字＝看動效的窗。漸層剪進字裡，而且會流 */
.mark {
  background-image: linear-gradient(110deg, var(--glow) 0%, var(--glow2) 28%,
    #fff 46%, var(--glow3) 68%, var(--glow) 100%);
  background-size: 260% 100%;
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
  filter: drop-shadow(0 0 34px rgba(79,70,229,.34));
  animation: flow 14s linear infinite;
}
@keyframes flow { to { background-position: 260% 0; } }
```

**淺底不能用白色當中間色點**，會直接消失。淺色主題要換成最深的那一個顏色。

```css
/* 二、顆粒。一張 SVG 噪點，不用圖檔也不用外部資源 */
.grain { position: absolute; inset: 0; pointer-events: none; opacity: .32;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E"); }

/* 三、暗角。把視線收到中間 */
.vignette { position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(120% 90% at 50% 45%, transparent 42%, var(--ink) 96%); }

/* 四、淺色主題共用同一支動效，把它反相就好 */
html[data-theme="light"] canvas { filter: invert(1); mix-blend-mode: multiply; }
```

```js
// 五、捲離首屏就淡掉，不要在下面一直吃效能也一直吵
new IntersectionObserver(function (es) {
  document.documentElement.style.setProperty('--heroOp', es[0].isIntersecting ? 1 : 0);
}, { threshold: 0.12 }).observe(document.querySelector('.stage'));
```

```css
/* 六、動效當主角的時候，文字底下要墊一層化開的暗罩，不然動效一亮就讀不到 */
.hero-text { position: relative; }
.hero-text::before { content: ''; position: absolute; inset: -12% -18% -18% -12%;
  background: radial-gradient(70% 70% at 32% 50%, rgba(5,6,10,.82) 0%, rgba(5,6,10,0) 72%);
  z-index: -1; pointer-events: none; }
```

**一個一定會踩到的坑：`<canvas>` 是替換元素，只寫 `inset: 0` 不會被撐開**，
它會維持 300×150 卡在左上角。滿版的 canvas 一定要寫 `width: 100%; height: 100%;`。
這個我踩過，畫面只有左上角一小團，看起來像動效壞掉。

**這一路仍然要守的三件事：** 文字讀得到（對比檢查照跑）、
`prefers-reduced-motion` 要能靜止、捲走要停算。
奔放不等於可以讓人讀不到字。

## 六種都不對的時候

先打開 `docs/effects.md`。那份會先要你確認真的需要，
再帶你去 90 個開源特效的目錄裡挑，並且說明怎麼包成同一套介面。

自己寫一支的話，照那五支的介面：
接 `(canvas, opts)`、回傳 `{ destroy }`、支援 DPR、
`prefers-reduced-motion` 要只畫一張靜態畫面、分頁切走要停掉迴圈。
這四件事是硬要求，少一件就會有人的電腦在背景燒電。

## 文案

**每一句都要是使用者自己講過的話，你只做刪修。**
你替他寫的漂亮句子，他之後唸給客戶聽會卡住。
訪談逐字稿裡挑出他講得最順的那幾句，那些就是文案。

首屏標題只講他做什麼、給誰。不要寫「歡迎來到我的網站」，
也不要寫任何一句換成別人也成立的話。

## 概念

訪談如果問出了一個屬於他的概念（`spec/site.yaml` 的 `concept`），
**排版之前先打開 `docs/concept.md`**，照那份做。

重點只有三句：只挑三個具體決定（一個形狀、一種字、一個重複元素），
概念只在首屏做足、內文回到乾淨，關掉概念元素之後這一頁還要讀得懂。

**`examples/` 裡有四個做完的範例**，四種行業各一個，
可以直接看概念是怎麼變成 CSS 的。那一份也整理了五個概念裡重複出現的五樣手法。

沒問出概念就跳過這一節，做乾淨的版面就好。

## 作品卡要不要寫「做多久」

想學的受眾很在意這個。實測的原話：
「這看起來像是一個強者的作品集，而不是教我怎麼做。他強調自己維護三十多個專案，
**反而讓我覺得這對我這種外行來說太難**。」

同一批作品加一行「用了什麼工具、多久做出第一版」，就從「別人的成就」
變成「我伸手可及的東西」。

**但那個數字最容易寫錯，兩個坑都實測過：**

**一、不要拿「第一個到最後一個 commit」當答案。** 那是維護的時間。
有個專案跨度 122 天，但第一版是同一天做完的，之後四個月都在加功能。
寫「花了 122 天」會嚇跑正是你想吸引的那種人。

**二、一定要排除自動化的 commit。** 有個每小時自動更新的專案，
含 bot 算出「前一半要 85 天」，排除之後是 **12 天，差七倍**。
每日自動擴充、定時抓資料、機器人回寫這類專案都會中。

**三、只看作者名字不夠。** workflow 如果用個人 token 推送，
作者就是本人，`[bot]` 那一套完全抓不到。
所以要**同時**去 `.github/workflows/` 把自動 commit 的訊息撈出來，用訊息再擋一次。

撈訊息也有一個坑：**不要只取變數前面那一小段當前綴。**
有個 workflow 的訊息是 `feat: 第 $N 話草稿(自動產出,待人工確認)`，
只比對 `feat: 第` 會把人寫的 `feat: 第三話——伺服器重啟中！` 一起擋掉。
要把整個模板轉成樣式、變數換成萬用字元，前後都對上才算。

用這支算，兩個坑都擋掉了：

```bash
node tools/effort.mjs ~/你的專案
```

它會直接吐一句可以貼上網站的話，例如
「一半的修改在一天內做完，之後陸續改了 27 天」，
並且列出它從 workflow 撈到的自動訊息樣式讓你核對。

**兩道都擋不住的情況它會警告你**：workflow 的訊息是純變數（像 `-m "$MSG"`）
而且又是用個人 token 推的，那種只能自己看 commit 紀錄判斷，數字會偏高。

**沒有 git 紀錄的專案就不要寫數字**，寫「用了什麼工具」就好。編一個時間比不寫更糟。

## 中文排版的數值

`docs/craft.md` 有一份問過三個模型家族收斂出來的清單，照級別分成
「直接做」「可選」「靈感」三級。三個都同意的只有三條，**那三條一定要遵守**：

- 破除置中（`margin: 0 auto` 是套版感最大的來源）
- 中文行高 1.8 到 2.0（英文慣用的 1.5 套到中文會擠）
- **標題不要用負字距**（全形字沒有側邊空間，再收會相碰）

模板已經照這三條設好了。**動 `tokens.css` 的時候不要改回去。**

那一份最後還有一節「怎麼量自己有沒有進步」，是可以重複跑的比對測試。
排版被說像模板的時候先跑那個，拿到具體理由再改，不要憑感覺調。

## 中文標題的斷行

中文沒有空格，瀏覽器會從標題的任何一個字中間斷開，窄螢幕上很容易斷出
「讓工廠的數／字自己說話」這種東西。**把標題依語意切成幾段，各包一個 span**，
模板的 CSS 已經把它們設成 `inline-block`，斷行就只會發生在段與段之間：

```html
<h1><span>讓工廠的數字</span><span>自己說話</span></h1>
```

手機上一定要親眼確認一次。這件事沒有純 CSS 的解，
`word-break: auto-phrase` 在中文上不會生效。

## 圖片

**打開 `docs/images.md`，照那份做。** 那份處理的是最常見的實況：
使用者手上沒有能用的圖。裡面有三種狀況各自的解法、尺寸與壓縮指令、
EXIF 要拿掉的理由，以及一條不能踩的紅線。

這裡只重複最重要的兩句：**沒有圖就選不吃圖的版面**（`editorial.html`），
不要放占位圖；**絕對不要用別人的照片或圖庫照片假裝是使用者本人或他的作品**，
他說「先放示意圖」也一樣。

## 可以搭的外掛

開始排版之前掃一眼 `docs/external-skills.md`。**使用者已經裝好的才用**，
不要自己去裝。最常派上用場的是 `frontend-design`（讓版面不要長成一眼看得出來是
AI 做的）跟 `theme-factory`（配色）。他沒裝就照這個 repo 內建的做完，
交付的時候提一句就好。

排版之前也把 `docs/inspiration.md` 再開一次，對齊野心。**看完就關掉。**
對著別人的站排版，做出來的一定是別人的站。

## 交出去之前

跑一次階段四的檢查再給使用者看。

