階段三:建站
動手之前先唸一次 avoid
spec/site.yaml 的 avoid 是使用者明講「絕對不要」的東西,抄的是他的原話。
排版之前唸一次,交出去之前再唸一次。
這一項很容易被忽略,因為它講的是「不要做什麼」,不會主動跳出來提醒你。 實測的例子:「不要像購物網站那樣一格一格標價錢放購物車」—— 那句話直接否決掉用卡片格排服務項目的做法,要改用條列。
先確認族,再談版面
docs/families.md 有七族:克制、訊號、圖鑑、霓虹街機、終端、粗獷、復古介面。
族是性格,概念是骨架,兩件事分開。 同一個概念可以做成不同族:
「工單」可以是克制的工程圖,也可以是粗獷的黑黃警示牌。
templates/ 裡的骨架目前只覆蓋兩族(克制與訊號)。
其餘五族沒有現成骨架,要照那一份的「關鍵手法」自己寫,
每一族都附了色彩配方、動畫的性格、三到五個 CSS 層級的手法與參考站。
族不對就整個重來,不要在錯的族裡調參數。 一個做電音的人配上克制族,字距與留白調到死都不會對。
概念夠強的時候,不要挑版面,用概念生一個
templates/ 那五種是沒有概念時的安全牌。訪談問出了概念,
就照 docs/concept.md 的三個問題生一個新的:
- 容器:每個區塊被裝在什麼裡面(一片面板、一張圖紙、一格片格、一列欄位)
- 重複單元:內容清單怎麼排(一台設備、一個件號、一格底片、一次會談)
- 分節:區塊之間怎麼編號(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。
挑好或生好之後開工:
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:
/* 一、名字=看動效的窗。漸層剪進字裡,而且會流 */
.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; } }
淺底不能用白色當中間色點,會直接消失。淺色主題要換成最深的那一個顏色。
/* 二、顆粒。一張 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; }
// 五、捲離首屏就淡掉,不要在下面一直吃效能也一直吵
new IntersectionObserver(function (es) {
document.documentElement.style.setProperty('--heroOp', es[0].isIntersecting ? 1 : 0);
}, { threshold: 0.12 }).observe(document.querySelector('.stage'));
/* 六、動效當主角的時候,文字底下要墊一層化開的暗罩,不然動效一亮就讀不到 */
.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: 第三話——伺服器重啟中! 一起擋掉。
要把整個模板轉成樣式、變數換成萬用字元,前後都對上才算。
用這支算,兩個坑都擋掉了:
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,斷行就只會發生在段與段之間:
<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 再開一次,對齊野心。看完就關掉。
對著別人的站排版,做出來的一定是別人的站。
交出去之前
跑一次階段四的檢查再給使用者看。