工程趣聞 2026 年 6 月 24 日

2026-06-24 — CSS 渲染 Quake、atproto 無實例架構、XP 作品集內嵌 Game Boy

primary=https://cssquake.com/ primary=https://overreacted.io/there-are-no-instances-in-atproto/ primary=https://mitchivin.com/

CSS 取代 WebGL?用純 CSS 在瀏覽器裡跑 Quake

cssquake.com · GitHub: LayoutitStudio/cssQuake · 2026-06-20

2026 年 6 月 20 日,一個名為 CSSQuake 的專案出現在社群視野中,讓 1996 年的 3D 射擊遊戲 Quake 完整跑在瀏覽器裡——不用 WebGL、不用 Canvas,只靠 CSS 3D 變換。背後的核心是一個叫做 PolyCSS 的自製渲染引擎,由 LayoutitStudio 開發並開源(GPL-2.0)。

PolyCSS:把 3D 幾何轉成 DOM 節點

傳統遊戲引擎在瀏覽器中幾乎都依賴 <canvas> 或 WebGL 將畫面逐幀光柵化。PolyCSS 走了完全不同的路:它把每個多邊形面片(polygon face)轉為真正的 HTML 元素,再透過 CSS matrix3d() 將其放置到 3D 空間中。世界裡的每一個可見面都是一個有位置的 DOM 節點,紋理則以 CSS background 屬性貼上,並啟用 image-rendering: pixelated 保留 Quake 的像素感。

這個方法帶來了幾個有趣的副作用:由於幾何體是真實 DOM,開發者工具的元素面板可以直接看到場景樹;而瀏覽器內建的合成層(composited layer)機制則可以替代部分渲染最佳化工作。整個場景透過 @layoutit/polycss 套件的 createPolyScene()createPolyPerspectiveCamera() 等 API 組合,以 TypeScript 撰寫,架構類似一個輕量的 3D 場景圖。

PolyCSS 的透視相機以 CSS perspective 屬性控制視景深度,第一人稱控制器(createPolyFirstPersonControls())則將滑鼠移動轉換為旋轉矩陣,再反映到相機元素的 transform 上。整個 3D 場景的「渲染」本質上是瀏覽器的 CSS 合成管線,而非 GPU 著色器管線。

資源準備管線:BSP、WAD、MDL 的瀏覽器化之路

Quake 的原始資源格式(.bsp 地圖、.wad 材質庫、.mdl 模型)在瀏覽器中無法直接使用,因此 CSSQuake 設計了一個離線的資源準備階段(src/prepare/assets.mjs)。整個準備管線的輸入是 Quake 1.06 共享版的 PAK 封裝檔案,輸出則是瀏覽器可直接掛載的 JSON 資料與 PNG/AVIF 紋理。

  • PAK 解析:以 Node.js Buffer 讀取封裝包,透過 parseQuakePakDirectory() 解出目錄結構,再逐一取出各資源。
  • BSP 地圖:轉換成 JSON,記錄頂點座標、面法向量、光照資訊,供執行期直接載入。
  • MDL 模型:依類型分組(怪物、武器、道具、彈射物),各自生成預編譯的渲染包(render bundle)。
  • 紋理:以 Quake 調色盤解碼後交由 Sharp 轉為 PNG,再依 AVIF 壓縮(預設品質 70)打包成紋理圖集(texture atlas),並以確定性(deterministic)命名確保快取有效性。

紋理圖集以 replaceQuakeRenderBundleWorldAtlas() 產生,並透過 textureFileUrlByHashtexturePngByPublicPath 兩個 Map 去重。讓增量更新不會讓舊快取失效,生成的靜態資源依功能分佈在 /t/(紋理)、/b/(渲染包)、/s/(音訊)、/w/(武器模型)等目錄下。

執行期架構:反應式流而非傳統 game loop

執行期(src/App.ts)採用流(flow)導向的反應式架構,而非一個巨大的 requestAnimationFrame 回呼。不同職責由獨立的 controller 和 flow 函數管理:

  • createQuakeAppInputController():處理 WASD 移動、滑鼠視角、空白鍵跳躍、Ctrl 蹲下等輸入。
  • createQuakeGameplayInputFlow():玩家物理與碰撞(QuakeCollisionWorld)。
  • createQuakeSceneMountFlow():將渲染包掛載到 DOM 並觸發可見性更新。
  • setQuakeRenderBundleFrameSetHandleFrame():逐幀更新動態幾何(門、平台、動畫材質序列)的 matrix3d 值。
  • createQuakeSoundController():音效事件管理。

地圖以 URL 參數共享狀態,格式直接使用 Quake 原生座標系,例如 ?map=e1m1&view=480,-192,72,0,90,0 表示地圖名稱加上 x、y、z 位置與 pitch、yaw、roll 旋轉角度(均以度表示)。分享特定視角或場景位置只需複製一段 URL,無需任何序列化工作。

效能現實與意義

CSS 3D 渲染最明顯的代價是 DOM 節點數量。Quake 的 e1m1 地圖有數千個面片,意味著數千個 DOM 元素同時存在於頁面中;瀏覽器的重排(reflow)和合成成本都比 WebGL 路徑高。CSSQuake 透過 BSP 可見面集(PVS)剪裁,各幀只更新可見節點,降低了不必要的 CSS 計算。它更重要的意義在於示範 CSS 3D 變換的邊界在哪裡——以及在瀏覽器的渲染管線中,DOM 與 GPU 合成之間潛藏的可能性。

原始來源:GitHub — LayoutitStudio/cssQuake


atproto 沒有「實例」這回事——Dan Abramov 解析去中心化的另一種思路

overreacted.io (Dan Abramov) · 2026-06-19

2026 年 6 月 19 日,React 核心貢獻者 Dan Abramov 在個人部落格 overreacted.io 發表了一篇技術文章,解釋為什麼人們常問的「Bluesky 的 instance 在哪裡?」其實是一個方向性錯誤的問題。文章的核心論點是:atproto 的去中心化模型從根本上與 ActivityPub 不同,不能用同一套概念套用。文章發佈後在技術圈廣泛流傳,因為它以淺顯的比喻點出了聯邦制(federation)與分散託管(distributed hosting)之間的架構差異。

三種模型:RSS、Mastodon、atproto

Abramov 用三個模型的對比來建立直覺。RSS 部落格時代是最早的分散式內容模型:每個人在自己的伺服器上存放內容,Google Reader 之類的服務只是「閱讀器」,它不擁有你的文章,你換掉閱讀器,內容還在原地。這個模型中,「託管(hosting)」與「聚合(aggregation)」是完全分離的。

Mastodon 採用的 ActivityPub 聯邦模型則把這兩件事捆在一起:每個 instance(例如 mastodon.social)同時負責存放用戶資料並提供應用程式介面。instance 之間透過明確的 ActivityPub 訊息互傳來同步,理論上這要求 instance A 知道要把 A 的貼文推送給哪些其他 instance,造成 O(n²) 的協調成本。用戶身份與 instance 綁定,alice@instance1.socialalice@instance2.social 是不同的人。

atproto 則選擇回歸 RSS 模式但在協定層標準化:用戶的貼文存放在 Personal Data Server(PDS),身份由 DID(Decentralized Identifier)綁定,而非由任何特定伺服器定義。Bluesky 的應用程式本身只是一個聚合層(aggregation layer),任何人都可以寫出自己的聚合器,讀取相同底層資料。Abramov 的比喻是:「你的貼文不『活在』Bluesky 這個 app 裡,就像你的 RSS 文章不活在 Google Reader 裡一樣。」

Relay 與 AppView:讓聚合可規模化

要讓多個應用程式能聚合來自全球所有 PDS 的資料,atproto 設計了兩層基礎設施。Relay(又稱 Firehose)負責訂閱所有 PDS 的事件流,將全網變更彙總成一條可訂閱的資料流,類似於 Kafka topic 的角色。AppView 則訂閱 Relay 的 Firehose,依照應用程式邏輯建立索引,例如 Bluesky 的社交圖譜、Tangled 的程式碼協作圖、Semble 的文章訂閱等。

這個設計讓聚合基礎設施可以由社群或第三方輕量運作:Abramov 提到,有些社群快取實作完全不需要獨立資料庫,因為它們可以從 Relay 的事件流即時重建所需的視圖。這與 Mastodon instance 需要維護一份完整的本地資料庫副本截然不同。

身份可攜性與去中心化的實際意義

Abramov 在文章撰寫期間示範了身份可攜性(identity portability):他在寫作途中把自己的 PDS 從預設提供商遷移到 Eurosky,Bluesky 上的追蹤者、歷史貼文、身份全部保留,對觀眾完全無感。這是因為他的 DID 指向的是他的資料,而不是某個特定的伺服器位址。傳統 ActivityPub 帳號遷移需要手動通知追蹤者、重新建立關係,且歷史貼文通常無法跟著走。

文章最後挑戰了用「instance 數量」衡量去中心化程度的習慣思維。在 Mastodon 生態中,instance 數量確實代表權力分散程度;但在 atproto 生態中,真正分散的維度是「有多少人自己託管 PDS」以及「有多少獨立應用程式從同一份資料建立不同的聚合視圖」。Abramov 認為這才是應該關注的指標,而非問「有沒有 instance」。

原始來源:overreacted.io — Dan Abramov


瀏覽器裡的 Windows XP:一個有可玩 Game Boy 和 iPod 的作品集網站

mitchivin.com · Show HN · 2026-06-21

2026 年 6 月 21 日,一位名叫 Mitch 的開發者在 Hacker News 上以「Show HN」形式分享了他的個人作品集網站,整個網站被設計成一個完整運作的 Windows XP 桌面環境,並在裡面內嵌了一台可玩遊戲的 Game Boy 和一個可操作的 iPod。這不是截圖或動畫,而是以 HTML、CSS、JavaScript 從零重建的互動式 UI 仿真。這個作品集的第一版(「Show HN: I recreated Windows XP as my portfolio」)在 2025 年 9 月首次亮相,本次更新加入了 Game Boy 模擬器與 iPod 介面兩大功能。

Windows XP 桌面:CSS 還原 2001 年的像素美學

重現 Windows XP 的視覺感需要大量細節考究。Mitch 透過 CSS 還原了 XP 標誌性的藍綠色漸層標題列、圓角視窗邊框、立體感按鈕以及工作列(taskbar)的「開始」按鈕。視窗的拖曳、最小化、最大化行為以 JavaScript 事件監聽配合絕對定位實作,模擬出 XP 視窗管理員的基本行為。桌面圖示可點擊開啟各個「程式」,每個程式都是一個獨立的浮動視窗元件。

整體架構以 SPA(單頁應用程式)方式組織,每個視窗是一個可獨立掛載的元件,z-index 管理決定視窗疊加順序,點擊視窗時會將其提到最前面,忠實重現了 XP 的視窗焦點行為。背景桌布是經典的 Bliss 草原圖,填滿視口以模擬 XP 的桌面背景。視窗標題列的漸層色使用 CSS linear-gradient#245edb#3d9eff 的 XP 藍復刻原色,連關閉按鈕上的紅色球形圖示都有對應的 CSS 實作。

Game Boy 模擬器:在作品集視窗裡跑 ROM

這個作品集最受注目的技術亮點是一個可實際執行 Game Boy ROM 的模擬器,被包裹在一個仿 Game Boy 外殼的 CSS 介面中,並以 XP 視窗的形式呈現於桌面上。模擬器核心採用既有的開源 JavaScript Game Boy 模擬器實作,整合至視窗元件後,玩家可以透過螢幕上的方向鍵和 A/B 按鈕操作,或使用鍵盤快捷鍵。

Game Boy 的外殼造型以純 CSS 繪製:機身的圓角矩形、螢幕的嵌入感、按鍵的立體陰影效果,都用 border-radiusbox-shadow 和漸層背景模擬。模擬器的畫面輸出以 <canvas> 元素呈現在 CSS 外殼內部,形成「CSS 外殼包裹 Canvas 畫面」的複合結構,既保留了 Game Boy 的視覺外觀,又讓模擬器核心直接以 Canvas API 輸出畫面,兩層職責清楚分開。

iPod:轉盤互動與音樂介面的純前端重現

同樣受到關注的是仿 iPod Classic 的音樂播放介面。iPod 外殼同樣以 CSS 繪製,最關鍵的技術挑戰在於重現 Click Wheel(點擊轉盤)的操作感。轉盤以 CSS 繪製的圓形區域配合 JavaScript 的滑鼠與觸控事件實作,透過計算觸控起始角度與移動角度的差值來模擬轉動行為,進而控制選單捲動速度。

iPod 的選單樹(Music → Albums → Songs 等層級)以 JavaScript 狀態機管理,每次中央按鈕按下或返回按鈕觸發對應的狀態轉換,畫面以 CSS transition 滑入滑出。音訊播放透過 HTML5 <audio> 元素串接,讓選中的曲目可以真正播放。整個 iPod 介面同樣被封裝成一個 XP 視窗,可以與桌面上其他視窗並排操作。

作品集作為技術展示的一種形式

這個專案在 HN 引發的討論多半圍繞在「作品集本身就是作品」這個概念:與其用一頁靜態網頁列出履歷,不如用一個互動系統展示你能做什麼。Mitch 坦言在開發過程中大量使用了 AI 程式碼協助工具,也因此觸發了部分社群關於 AI 輔助開發邊界的討論。不論如何,這個作品集示範了前端工程師如何把 CSS 佈局、DOM 事件管理、JavaScript 狀態機、瀏覽器音訊 API 和第三方模擬器整合成一個有凝聚力的互動體驗——而這個整合本身,就是技術能力的展示。

原始來源:mitchivin.com · HN 討論


End of article
0
Would love your thoughts, please comment.x
()
x