回作品列表 Side Project

Bitmap Dream

零依賴的點陣抖色引擎,把照片與數學密度場變成純 SVG 的復古點陣插畫

角色
生成式引擎、前端實作、互動設計
期間
2026.04 – 2026.06
範疇
生成式藝術、SVG、TypeScript、點陣抖色、React Playground
Bitmap Dreams 互動工作檯——左側場景/照片/圖層面板,中央畫布是一張紫色點陣抖色插畫
6
種筆觸渲染器
0
執行期依賴
186
測試全過
15+
預設場景

背景與挑戰

我一直撞到同一道牆:side project 需要插畫,但素材庫的圖太通用,真實照片又常常配不上世界觀;而每個專案都委外或手繪視覺,根本撐不起多專案的量。所以 Bitmap Dream 的目標是不要再找素材,而是把素材「長出來」——一個引擎,把一張照片、或一段純數學,變成可以隨時換皮、換色、換種子碼的復古點陣插畫。

硬性條件是:產出必須是能上線的等級,而且可攜。它要能跑在瀏覽器裡做互動 playground,跑在 Node 裡做測試,也要能塞進建置腳本、讓採用端把結果當成靜態 SVG 內嵌。這就排除了所有 canvas 像素的取巧寫法與任何執行期依賴。引擎必須是純函式:餵進像素、吐出 path;同一個 seed 進去,永遠是同一張圖出來。

方法與工藝

整條管線一句話就講得完:密度場描述一張圖哪裡深、哪裡淺,量化器把這個連續的場收斂成有限的階數,最後由筆觸渲染器決定每一格實際長什麼樣。這樣切分的好處是,任何一段都能單獨替換而不動到其他段——同一個密度場,只改最後一步,就能從 halftone 海報變成斜紋版畫。

同一顆放射狀日盤密度場,並排走六種筆觸:方塊(Bayer 8×8)、顆粒(blue-noise)、halftone 圓點、掃描線、斜紋、交叉線;中央實心盤六格完全相同,外圍紋理各異
同一個密度場(footer 那顆放射日盤)餵給六種筆觸渲染器——中央實心盤完全一樣,變的只有筆觸幾何
同一張掃描線渲染的日盤,並排換三套雙色調色盤:靛橙、紫色雙色、單色靛;三格的掃描線幾何完全相同,只有顏色不同
同一張掃描線輸出、三套調色盤重新上色:站內靛橙、起源的紫、單色靛——三張共用同一份 path,換色不重算半點

決定性是整件事的脊椎。所有隨機都來自種子碼,所以一個場景完全可複現、可版本化、可測試——186 個測試把輸出釘到一模一樣。渲染端則用 RLE(run-length encoding)把同階的格子合併,一片平坦區域於是收成單一條 path,而不是幾千個矩形,讓 SVG 的節點數與檔案大小都維持在理智範圍。

成果與反思

Bitmap Dream 的第一場實戰,就是當本作品集的生成式視覺層。它的渲染器被 vendor 進站,在建置期直接內嵌成 SVG:hero 那張點陣肖像、每張專案卡上的 riso 方章、footer 的日蝕,再加上全站那層固定的點陣背景——全在站內靛橙雙色調色盤下生成,沒有一張是手繪的。其中 hero 肖像正好踩到引擎「真實照片 → 密度場」那條分支:一張我的照片被轉成密度、再交給筆觸渲染,證明 field 這一層不只吃數學。而且這些視覺都是內嵌、不是 <img>,所以兩個墨色被換成 CSS 變數,會跟著淺/深主題一起翻色。

這次採用又直接回饋回引擎本身。最大的一課來自採用端:scanlines 每格輸出一個矩形、不做水平合併,所以一張全幅大圖會讓 path 數暴增、檔案爆量。採用端的解法是把 grid 壓小、用小尺寸場景收尾——同時也記下了引擎端清楚的下一步:為 scanlines 加上同列合併最佳化。另有一個已知限制:斜紋與交叉線在「匯出單張拼貼磚再用 CSS 重複」時,邊緣會被裁出淡淡的接縫;一般預覽不受影響,正解是讓筆觸環繞拼貼磚描繪,已列入後續。

這個專案的主軸,是它逼著我換了做視覺的方式:與其找素材,不如把美術方向翻譯成程式能據以生成的規則。引擎本身就成了資產——而一旦它住進建置流程,每個採用它的專案都能免費獲得一套一致、可重新上色、可無限重新下種的插畫系統。