Community影像github.com

顆粒漸層

給 CSS 漸層和背景鋪上一層膠片顆粒,讓它們像印刷品而不是塑料,並壓掉色帶。

顆粒漸層 是什麼?

技能會掃描整個網站或單塊背景,列出填色,再讓人挑選要處理的那些。它量過每條漸層,自己決定混合方式和用量,在真實頁面上給出前後對比,並寫出能適應 HDR、OLED、高對比度和列印的 CSS。漸層顯得廉價、有條紋或過於光滑時用它。

相容平台✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Farhad1618/grainy-gradients/tree/HEAD/skills/grainy-gradients

Installed? Explore more 影像 skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

顆粒漸層 是做什麼的?

平滑的數位漸層看起來很「電腦化」。細微的噪點層能讓它們呈現印刷或底片質感,並隱藏條帶(漸層從一個8位元色彩層級過渡到下一個時出現的可見條紋)。

你完成所有工作。使用者只需觀看並選擇。 絕對不要詢問關於混合模式、不透明度或數值的問題。使用者只做三種決定,別無其他:

  1. 哪些背景(僅當你掃描了整個網站時)。
  2. 是否先看前後對比,或直接套用。
  3. 在預覽中哪個選項看起來最好。

如何思考

  • 顆粒是紋理,不是色彩。 它不能變亮、變暗或染色。噪點以中灰色為中心,因此亮度偏移應接近0。它不能用於純黑或純白,報告會說明原因。

  • 測量可見部分,而非不透明度。 可見顆粒是L*(CIELAB亮度,0–100)的擴散範圍,且L*是感知性的,因此相同數值在任何顏色上看起來都差不多。低於約0.45時沒有人能看見。目標值為Subtle / Medium / Strong分別對應0.5 / 0.8 / 1.4。

  • 均勻分佈在明暗漸層上也有效。 Overlay會將大部分顆粒集中在較亮的部分。Even則選擇(通常為柔光)能更均勻分佈顆粒的混合模式。人們通常偏好這個。

  • 顆粒屬於背景。 它位於背景正上方,在所有其他元素之下,並跟隨背景移動。如果背景淡入,顆粒也會隨之淡入。

  • 它適應每位訪客的螢幕。 網站無法區分OLED和LCD,但CSS可以區分HDR螢幕(大多數OLED手機、XDR筆電)和高對比度設定。CSS包含這些媒體查詢:

    • 深色背景在HDR螢幕上獲得略少的顆粒
    • 高對比度設定獲得較少顆粒
    • 列印時關閉顆粒

    全部由CSS實現,無需腳本。

  • 跳過顆粒無法改善的情況:

    • 小型元素(按鈕、徽章、圖示)
    • 漸層文字
    • 照片上方的半透明遮罩和淡入效果
    • 條紋和影線圖案

1. 他們以哪種方式提出需求?

  • 單一位置(「主視覺看起來很平」、「為頁尾添加顆粒」):前往 尋找單一背景。
  • 整個網站或應用程式(「檢查我的程式碼庫」、「檢查所有漸層」、「處理整個網站」):前往 掃描整個網站。

2a. 尋找單一背景

找到實際繪製背景的元素。檢查:

  • 元素本身,以及其 ::before 和 ::after
  • 元素內部或後方的全尺寸圖層(區塊通常從一個獨立的絕對定位div獲取顏色)

使用瀏覽器工具列出候選元素:

[...document.querySelectorAll('#section, #section *')].flatMap(e => [null, '::before', '::after'].map(p => [e, p, getComputedStyle(e, p)]))
  .filter(([, p, c]) => (!p || c.content !== 'none') && (c.backgroundImage !== 'none' || c.backgroundColor !== 'rgba(0, 0, 0, 0)'))
  .map(([e, p, c]) => `${e.tagName.toLowerCase()}${e.id ? '#' + e.id : ''}.${[...e.classList].join('.')}${p || ''} | ${c.position} | opacity ${c.opacity} | ${(c.backgroundImage !== 'none' ? c.backgroundImage : c.backgroundColor).slice(0, 80)}`)

如果沒有瀏覽器,請閱讀CSS。無論哪種方式,在CSS中搜尋該背景的其他版本:媒體查詢(手機佈局通常會切換漸層)和深色模式規則。記下它們以備步驟5使用。

然後前往 步驟3。

2b. 掃描整個網站

node <此技能資料夾>/scripts/scan.mjs <專案資料夾>

它會在大約一秒內讀取樣式表(規則、媒體查詢、自訂屬性)、標記和元件(Tailwind漸層類別、行內樣式、CSS-in-JS)。它將找到的內容分為四組:

  • 良好候選: 大型背景。
  • 值得一看: 從程式碼中無法得知大小。
  • 已有顆粒。
  • 跳過, 附帶原因。

它還會列出每個樣式表載入的頁面。加上 --json 以獲取完整資料。

自行排序「值得一看」的項目。 在顯示清單之前,根據你能看到的內容進行排序。使用瀏覽器工具在頁面上測量它們的大小。否則請閱讀標記。將每個項目移至良好或跳過。不要將你可以檢查的項目清單發送給使用者。

然後顯示清單, 簡短、每行一個,用淺白語言描述,按頁面分組。例如:

我找到6個可以添加顆粒的背景:

  1. 首頁,導覽區塊: 淡入的深色漸層
  2. 首頁,主視覺: 深色放射狀光暈
  3. 永續發展,頁首: 綠黑漸層
  4. 職涯,「在此製造」區塊: 橘黑漸層

跳過12個:按鈕、漸層文字、照片遮罩和條紋圖案。 報價頁面已有顆粒,但濃度無人能見,因此我會重做。

然後讓他們選擇。 如果你有多選題工具(Claude Code中的AskUserQuestion),請使用它:

  • 詢問「哪些背景應獲得顆粒?」並將 全部(推薦) 放在首位。
  • 最多再列出3個項目,每個作為一個選項,啟用多選。
  • 如果超過4個,先問「全部,還是選擇?」;如果選擇「選擇」,則每次以最多4個項目為一組詢問多選問題。

如果沒有該工具,請要求他們回覆「all」或數字。

3. 詢問:前後對比,或直接套用?

對於所有選定項目只問一次:「你想先看前後對比,還是直接為每個套用最佳選項?」如果你有多選題工具,請使用它,提供 先給我看(推薦) 和 直接套用。

以下工具需要 Node 22+ 和機器上的 Chrome、Chromium、Edge或Brave(自動尋找;CHROME_PATH 可覆蓋)。它們以無頭模式開啟頁面,因此網站必須可達:執行中的開發伺服器、暫存URL,或純HTML的 file://。不會對網站添加任何內容。

4. 顯示前後對比

先給我看:檢閱頁面

在背景執行(它會等待使用者),每個頁面使用一個 --url,後面跟著該頁面的選擇器:

node <技能>/scripts/review.mjs --url http://localhost:3000/ --selector ".hero" --selector ".footer-band" \
                                --url http://localhost:3000/about --selector ".about-header"
  • 它自行拍攝圖片。 對於每個背景,它拍攝頁面原始狀態以及每個選項下的照片,還有HDR螢幕和高對比度設定下的效果。每個頁面大約需要10–30秒。
  • 然後在他們的瀏覽器中開啟一個本機檢閱頁面並列印其網址;也給他們連結。
  • 每個背景獲得一張卡片,包含:
    • 前後對比滑桿
    • 縮放條帶,放大條帶最嚴重的區域(細微顆粒在縮小的圖片中不可見)
    • 以分頁顯示選項,推薦選項標有星號
    • 螢幕切換
    • 測量數值,以及包含報告的「為什麼」
  • 「完成,傳送我的選擇」 直接將選擇傳回。無需複製貼上。

用一句話告訴他們要做什麼:「拖動每張圖片,嘗試縮放,為每個背景選擇一個,然後按下完成。」當命令結束時,其輸出包含選擇、每個背景的CSS,以及每個背景的基準資料夾(用於步驟7的檢查)。

同時在聊天中顯示一張圖片。 每個基準資料夾包含 compare-<option>.png:

  • 完整的前後對比
  • 放大的細節
  • 相同細節,但對比度被拉伸,使條帶顯示為條紋,顆粒顯示為噪點
  • 測量數值

將推薦的選項發送給使用者(如果你有檔案傳送工具則使用它;否則提供路徑)。這是變更真實存在的證據。

直接套用

先拍攝基準圖片和照片,以便稍後檢查和顯示結果:

node <技能>/scripts/shoot.mjs --url http://localhost:3000/ --selector ".hero" --option recommended --out ./grain-shots

它會為每張圖片列印一行(顆粒、亮度、條紋寬度),並在 <out>/<selector>/ 目錄下寫入 report.json(報告、每個選項的CSS、推薦選項)和 compare-<option>.png。使用 report.json 中的推薦CSS。

沒有Chrome,或無法以無頭模式存取網站

回退到頁面內預覽:將 dist/grain-page.js 複製到網站自己的腳本旁邊(檢查它是否載入成功,返回200而非404),新增 <script src="/js/grain-page.js" data-grain=".hero | .footer" defer></script>,然後讓他們開啟帶有 ?grain 參數的頁面。它會在真實頁面上顯示相同的選項,並帶有可拖動的手柄;複製選擇 會複製 grain: <option> 以及每個背景的外觀,你可以將其傳送給 node <skill>/scripts/grain.js --look - 以獲取CSS。之後刪除標籤和檔案。

如果完全沒有瀏覽器,請自行編寫外觀並對其執行 grain.js:

{ "selector": ".hero", "kind": "gradient", "shape": "linear",
  "colours": [{ "colour": "#323435", "pos": 0 }, { "colour": "#141617", "pos": 1 }],
  "lengthPx": 900, "background": "linear-gradient(...)", "behind": "#ffffff",
  "solidBase": true, "position": "relative", "freePseudo": "::after", "moves": null }

或執行 node grain.js --colours "#323435,#2a2c2d@24%,#141617" --length 900 --selector ".hero" [--shape radial] [--fade-over "#fff"] [--option even]。

引擎的決策,讓你無需操心

情況作用方式
元素上的漸層或純色一層: 噪點成為元素的頂層背景(background-blend-mode),儲存在 --grain 自訂屬性中。每個背景清單新增一個值,因此頁面自身的大小、位置和混合模式得以保留。它不會覆蓋文字。
背景淡入同一層,因此顆粒隨之淡入。報告會給出淡入每個階段的顆粒值。
半透明漸層,下方無固色自己的圖層(一個自由的 ::after/::before,或一個子元素),以便與穿透顯示的內容混合,而不是變成灰色。
照片或圖片背景一個自由的偽元素,如果兩者都被佔用則使用子元素。
填充元素的 <img>/<video>,或偽元素上的背景隔離主機中 z-index: -1 的子元素。
純黑或純白Overlay和soft-light無法在那裡添加顆粒,因此它會使用screen或multiply,並帶有微小的亮度偏移,並且會說明原因。
跨漸層的顆粒不均勻如果Even明顯更均勻,則推薦Even。當Even與Medium相同時隱藏Even。
高條帶風險說明所選顆粒是否會打散條紋。Strong效果更強。
同一背景中的舊噪點層取代它。如果舊噪點在其他地方(偽元素),則說明要移除它。
在WebGL/canvas場景中繪製的背景部分(3D地面、著色器背景)canvas後方的CSS顆粒無法觸及它,因此canvas部分在顆粒化的天空旁邊看起來平滑或有斑點。你 添加它:在該材質的片段著色器中,在色彩空間轉換之後,於螢幕空間中柔光混合相同的噪點瓷磚(gl_FragCoord.xy / tilePx,tile = 200 × 渲染器像素比)。從頁面的 --grain 自訂屬性讀取瓷磚和濃度,以便手機、HDR和高對比度濃度得以延續,並在調整大小時重新讀取。透過渲染一幀並讀取像素來測量。
HDR螢幕、高對比度、列印@media (dynamic-range: high) 和 @media (prefers-contrast: more) 為這些螢幕重新計算濃度,使用相同的混合模式。@media print 將其關閉。結果相同的規則會被省略。

顏色根據它們在漸層中覆蓋的比例進行加權。細微的高亮不如大的深色區域重要,因此手機和桌機版本的相同區塊會獲得相同的處理。

5. 套用

  • 將每個CSS區塊放在該背景定義的位置, 附帶其註解。
  • 保留專案自己的背景表達式。 引擎從計算值開始工作,因此請將 var(--slate) 或原始的 linear-gradient(...) 放回輸出中重複的已解析漸層處。
  • 處理每個版本的背景(手機、深色模式)。一層CSS放在相同選擇器上,位於相同的媒體查詢內。如果版本不同,使用 --phone 或 --colours 測量每個版本。
  • 子元素方法: 在註解指定的位置新增 <div class="grain-layer" aria-hidden="true"></div>(在元件中,在其標記內)。
  • 為重複的噪點URL使用一個自訂屬性。 如果多個規則使用同一個,請定義一次。
  • 如果報告列出「頂部淡入效果」, 如所述為每個淡入效果提供相同的顆粒,否則在其最深處會再次出現條帶。
  • 移除任何臨時內容(預覽標籤、grain-page.js)。

6. 每次都要檢查

在說完成之前,根據基準檢查每個背景:

node <技能>/scripts/check.mjs --url http://localhost:3000/ --selector ".hero" --baseline <基準資料夾> [--option even]

它會再次拍攝頁面,並為以下各項列印PASS/FAIL:

  • 顆粒層 存在於頁面中(CSS已載入並作用於正確選擇器)。
  • 頁面上沒有新錯誤。
  • 顆粒 接近預期濃度。
  • 亮度 沒有移動。
  • 條紋 變窄了。
  • 背景外部沒有改變。
  • 沒有元素移動 或改變大小。

它會寫入 check.png,顯示之前與現在的對比。如果任何FAIL,請修復並重新執行檢查; 不要在失敗時報告成功。如果某個FAIL無法修復,請確切告訴使用者是哪個檢查失敗以及原因。

7. 報告

每個背景一兩句話,或整個網站的一個簡短清單:它是什麼、選擇了什麼以及原因。加上檢查的測量結果(例如「顆粒0.83 L*,條紋80px → 0.7px,無其他變化」),並發送 check.png 或 compare 圖片。說明一次該顆粒適應HDR螢幕和高對比度設定,並在列印時關閉。如果報告指出該目標尚未經由目視確認,請簡短說明。

後續調整

  • 「太多」或「看不見」: 移動一個層級。

…

[為翻譯而截斷]

相關技能