Q Square ESG

Client
Q Square 京站時尚廣場 (shopping mall, Taipei Main Station)
Agency
ES Design
Year
2026 (in progress)
Role
Front-end: production WebGL engineering, 3D scroll effects, Section 2, page transitions, QR coupon, mobile performance
Design
Eason (key visual, 3D direction, desktop UI), Melody (wireframes, tablet/module/game UI)
Stack
Nuxt 4, three.js, GSAP ScrollTrigger, Locomotive Scroll (Lenis), Node test runner, CDP scripts

ESG reports are usually PDFs nobody opens. Q Square wanted theirs as a site people would actually scroll through, built as a 3D journey around the mall and its green initiatives.

ESG 報告書通常是一份沒人會打開的 PDF。京站想把它做成大家真的會往下滑的網站:一段繞著商場和綠色行動走的 3D 旅程。

Starting point

A teammate had built a strong three.js prototype as a single 850-line file. My job was to make it production code without losing what made it feel good. I split it into scene, entrance and layout modules, moved the timeline logic into pure functions with unit tests, then built the rest of the experience on top.

同事先做了一個很漂亮的 three.js 原型,整個寫在一支 850 行的檔案裡。我的工作是把它變成能上線的程式碼,同時保住它原本的手感。我把它拆成場景、進場、版面三個模組,時間軸邏輯改成純函式並補上單元測試,再往上把整個體驗做完。

The hero

A camera path exported with the GLB is driven by scroll. I set the animation clip's time from scroll progress and step the mixer by zero, so the camera sits exactly where the scroll says and nothing drifts between frames. Points in the scene are projected to screen space every frame to position text cards and their connector lines, so the copy stays attached to the building as the camera moves. On the way out, the hero clips into an ellipse that hands over to the next section.

GLB 裡帶的相機路徑由捲動控制。我依捲動進度設定動畫時間,再讓 mixer 前進 0,相機就會停在捲動指定的位置,幀與幀之間不會漂。場景裡的錨點每一幀投影到螢幕座標,用來擺文字卡和連接線,相機移動時文案會一直黏在建築上。往下離開時,hero 會收成一個橢圓,交棒給下一段。

Section 2: the pillars

A 500vh pinned section. A green circle rises and keeps growing as you scroll. Inside it, an instanced forest of trees rushes past with speed streaks, faster the faster you scroll. Cards and photos fly in on the same timeline. The tree scene only starts when it's about to be needed and pauses when it's off screen.

一段 500vh 的 pinned 區塊。綠色圓形隨捲動升起、持續放大,圓裡有一片 instanced 森林帶著速度線往後衝,滑越快衝越快。卡片和照片跟著同一條時間軸飛進來。樹林場景要用到前才初始化,離開畫面就暫停。

Transitions

A door-panel "curtain" transition taken directly from the Figma frames. The same component handles first load and route changes, so the site opens and navigates with one consistent gesture.

照 Figma 畫面做的「開門」轉場。第一次進站和換頁用同一個元件,整個網站開場跟跳頁都是同一個動作。

Making it survive iPhones

iOS Safari kills tabs that use too much GPU memory, and two WebGL scenes on one page got there quickly. I wrote a script that measures memory, live WebGL contexts and texture counts on a device. Then I added render profiles: DPR capped at 1.5, no antialiasing or stencil on mobile, low-power preference, and contexts released after a delay once a scene is off screen. Visual acceptance runs automatically over Chrome DevTools Protocol, so regressions show up before a client does.

iOS Safari 會直接把吃太多 GPU 記憶體的分頁關掉,一頁兩個 WebGL 場景很快就到上限。我寫了一支腳本在實機上量記憶體、WebGL context 數量和貼圖數,接著加上渲染設定檔:DPR 上限 1.5、手機關掉抗鋸齒和 stencil、要求低功耗,場景離開畫面一段時間後釋放 context。畫面驗收透過 Chrome DevTools Protocol 自動跑,退步會在客戶看到之前先被抓到。

Credits

Project management: Ingia, Melody. Key visual, 3D direction, desktop UI and the original three.js prototype: Eason. Wireframes and tablet/module/game UI: Melody. Game back-end: Tommy, Melody. Front-end: Les.

專案管理:Ingia、Melody。主視覺、3D 方向、桌機 UI 與 three.js 原型:Eason。線框與平板/模組/遊戲 UI:Melody。遊戲後端:Tommy、Melody。前端:Les。

Next Chan Kee 陳記點心