← Tất cả bài viết
Thiết Kế Website Thương Hiệu Biến Đổi Như Ánh Sáng
Cách dựng website thương hiệu biến đổi cho fromanother — ánh sáng làm ẩn dụ chủ đạo, video-layering thay vì shader, và phần craft được Awwwards chọn làm case study.

Có thương hiệu đưa bạn một cái logo và bảng màu. fromanother đưa một brief khó hơn: dựng một website thương hiệu biến đổi cho một studio từ chối bị đóng khung là agency, studio hay collective. Chính sự "trôi chảy" đó là identity. Đây là câu chuyện nó được engineer ra sao — ánh sáng làm ẩn dụ tổ chức, video-layering thay vì shader, và Three.js chỉ dành cho đúng một tương tác thực sự xứng đáng. Awwwards vừa đăng bản build này thành một case study biên tập, Designing for an Identity That Shapeshifts — một trong số rất ít case study đầy đủ mà đội biên tập của họ đăng mỗi tháng — nên bài này là phần "nhìn từ góc developer" đi kèm với nó.
Tôi dựng fromanother.love với vai trò creative developer; fromanother giữ creative direction và là người viết bài Awwwards đó. Nếu bạn muốn bản "uy tín và giải thưởng" — FWA of the Day, Awwwards Site of the Day và Developer Award — thì đó là case study fromanother. Bài này là phần craft nằm bên dưới: các quyết định, code, và những chỗ đã vỡ.
Ánh sáng là design system, không phải trang trí
Concept fromanother đặt ra chỉ có một: ánh sáng. Không phải một hiệu ứng chiếu sáng — ánh sáng như hành vi của cả giao diện. Những vệt sáng cuộn, chuyển động, vô hình, tạo nên môi trường, còn nội dung giữ sạch và tối giản bên trên. Một khi chấp nhận đó là design system, rất nhiều kiểu motion web thông thường trở thành sai. Ánh sáng không trượt vào từ bên trái. Nó không snap. Nó không cut. Nó nở ra, loang, và khuếch tán.
Nên quy tắc đầu tiên là loại trừ: không trượt, không snap, không cắt cứng ở bất cứ đâu. Mọi reveal
phải đọc lên như ánh sáng đang tới hoặc tan đi — trong thực tế nghĩa là blur và opacity, không
phải dịch chuyển x/y. Chỉ một ràng buộc đó đã định hình hệ thống motion, các page transition, và
cả cách chúng tôi phân phối media nền.
Video-layering thay vì shader (cú "cheat" chiến lược)
Cách hiển nhiên để làm một nền fluid chạy bằng ánh sáng là dùng fragment shader — noise field, flow
map, bộ đồ nghề WebGL quen thuộc. Chúng tôi cố ý không làm vậy. Các color-state nền trên
fromanother.love là video xếp lớp, blend bằng mix-blend-mode và cross-fade trên opacity.
Lý do thuần là bài toán đánh đổi. Một tấm "light plate" cinematic tự dàn dựng — footage thật, đã grade màu — đọc lên giàu hơn hầu hết noise procedural, ship dưới dạng video nén mà CDN vốn đã biết cách stream, và gần như không tốn gì trên main thread. Một shader đẹp ngang thế sẽ tốn công viết, tốn tài nguyên chạy, và khó art-direct hơn. Như fromanother viết trong bài Awwwards: "Mục tiêu chưa bao giờ là xây thứ gì đó ấn tượng về kỹ thuật cho riêng nó. Mà là làm ra thứ cảm thấy đúng, và giấu kỹ phương pháp xuống dưới."
Đây là hình dạng của việc xếp lớp — hai (hoặc hơn) light plate, blend và cross-fade khi đổi state:
// Hai light plate xếp chồng; lớp mới fade lên trong khi lớp cũ fade xuống.
// mix-blend-mode tạo cảm giác "ánh sáng cộng dồn"; opacity lo phần chuyển cảnh.
function LightBackground({ state }: { state: 'warm' | 'cool' }) {
return (
<div className="light-stage" aria-hidden>
<video
src="/light/warm.mp4"
autoPlay muted loop playsInline preload="metadata"
style={{ mixBlendMode: 'screen', opacity: state === 'warm' ? 1 : 0 }}
/>
<video
src="/light/cool.mp4"
autoPlay muted loop playsInline preload="metadata"
style={{ mixBlendMode: 'screen', opacity: state === 'cool' ? 1 : 0 }}
/>
</div>
)
}
Việc đổi opacity được điều khiển bằng GSAP để cross-fade dùng một ease giống ánh sáng thay vì transition CSS tuyến tính:
gsap.to(incoming, { opacity: 1, duration: 1.4, ease: 'power2.inOut' })
gsap.to(outgoing, { opacity: 0, duration: 1.4, ease: 'power2.inOut' })
mix-blend-mode: screen là thứ khiến nó đọc lên là ánh sáng chứ không phải overlay — screen chỉ
làm sáng lên, đúng cách ánh sáng thật cộng dồn. Một dòng CSS làm đúng việc mà cả một shader phải vật
lộn. Đây cũng chính là bản năng "ưu tiên tính năng nền tảng trước khi tự viết engine" đằng sau
quyết định displacement-hay-CSS trong bài hiệu ứng hover WebGL.
Chữ hiện ra như ánh sáng: blur + fade, không bao giờ trượt
Khi đã loại bỏ trượt, các reveal tiêu đề tựa hoàn toàn vào blur và opacity. GSAP animate filter
của CSS, nên một dòng chữ hiện ra từ trong ánh sáng thay vì bay vào:
gsap.from('[data-light-in]', {
autoAlpha: 0,
filter: 'blur(14px)',
duration: 1.2,
ease: 'power2.out',
stagger: 0.08,
scrollTrigger: { trigger: '[data-light-in]', start: 'top 80%', once: true },
})
Hai lưu ý production quan trọng. Thứ nhất, animate filter: blur() là một thao tác paint, không
phải compositor — rẻ hơn shader nhưng không miễn phí, nên nó ổn cho vài dòng tiêu đề lúc enter và sai
với bất cứ thứ gì liên tục hay diện tích lớn. Thứ hai, luôn ghép với autoAlpha (kết hợp
visibility + opacity của GSAP) để một dòng đang mờ-chưa-hiện không bị trình đọc màn hình đọc hay bị
con trỏ bắt giữa chừng. Bản thân "ngữ pháp" reveal — một ease, một thang duration, ScrollTrigger gác
cổng — là cùng kỷ luật hệ-thống-motion tôi mổ xẻ trong bài
hướng dẫn GSAP ScrollTrigger.
Page transition loang và khuếch tán
Chuyển route là bài kiểm tra lớn nhất của ẩn dụ ánh sáng. Một crossfade thông thường chỉ là cú cut trá hình. Thay vào đó, transition loang và khuếch tán: trang cũ tan dần lên thành một mảng sáng, trang mới hiện ra từ trong đó — cùng ngôn ngữ blur-và-opacity như phần chữ, phóng ra cả viewport.
Trong Next.js App Router, phần đó nằm ở một lớp transition phủ trên route, và trang mới được giữ lại cho tới khi light plate đầu tiên của nó sẵn sàng để bạn không bao giờ khuếch tán vào một khung trống. Điểm mấu chốt là lớp phủ này là một timeline, không phải hai fade độc lập — phần out và in dùng chung một đồng hồ để cú bàn giao đọc lên như một lần nở sáng liền mạch chứ không phải hai sự kiện. (Về cơ chế route transition App Router nói chung, bài này đi cặp với bài trụ về thiết kế website tương tác immersive.)
Nơi Three.js thực sự xứng đáng: hiệu ứng ripple
Đây là phần kỷ luật mà Awwwards nhấn mạnh — biết hiệu ứng nào nên cheat và hiệu ứng nào phải build thật. Gần như mọi thứ fluid trên site là video và blend mode. Đúng một tương tác được xử lý WebGL đầy đủ: ripple trên thumbnail dự án, nơi hình ảnh gợn sóng như hòn đá ném xuống mặt nước tĩnh dưới con trỏ.
Cái này xứng với Three.js vì nó thực sự tương tác và có tính hình học — nó phản ứng theo vị trí con trỏ và thời gian theo cách không thể giả bằng video dựng sẵn. Nó là một plane, một texture, và một displacement shader chạy bằng uniform con trỏ:
const uniforms = {
uTexture: { value: thumbnailTexture },
uPointer: { value: new THREE.Vector2(0.5, 0.5) },
uTime: { value: 0 },
uStrength:{ value: 0 }, // ease 0→1 khi hover, 1→0 khi rời
}
useFrame((_, dt) => {
uniforms.uTime.value += dt
// ease strength về mục tiêu hover để ripple lắng lại, không bao giờ snap
uniforms.uStrength.value = THREE.MathUtils.damp(
uniforms.uStrength.value, hovering.value ? 1 : 0, 6, dt,
)
})
Gói trong React Three Fiber, cả thứ này chỉ vài chục dòng và chỉ chạy cho đúng thumbnail dưới con trỏ. Phần khó không phải shader — mà là containment: giữ ripple trong biên của ảnh thay vì loang ra khắp màn hình. Chỗ đó tốn tuning thật (clip UV bị dịch, clamp strength ở rìa) và đúng là kiểu WebGL "phẫu thuật" mà bài tối ưu hiệu năng Three.js nói tới.
Cuộc chiến hiệu năng: ánh sáng thì nặng
Ánh-sáng-bằng-video thì đẹp và nặng. Các trang dự án dày media là cuộc giằng co liên tục giữa thời gian tải và chất lượng, và bài học lớn nhất là về phân phối video.
Chúng tôi bắt đầu trên Vimeo và chạm trần của nó với kiểu dùng autoplay có lập trình, xếp lớp
blend-mode như thế này. Chúng tôi thử Gumlet và Mux — mỗi bên có logic delivery khác nhau — và phải
làm lại cách site request và stream footage quanh bên được chọn. Bài học cho ai dựng site nặng video:
player không phải phần khó; đường ống phân phối (HLS thích ứng, poster frame,
preload="metadata", rendition theo từng thiết bị) mới là nơi hiệu năng thực sự nằm.
| Vấn đề | Cách ngây thơ | Thứ đã ship |
|---|---|---|
| Nền fluid | Fragment shader | Video xếp lớp + mix-blend-mode: screen |
| Reveal chữ | Trượt + fade | Blur + autoAlpha, chỉ blur lúc enter |
| Page transition | Crossfade (một cú cut) | Loang & khuếch tán chung timeline |
| Hiệu ứng thumbnail | Video overlay | Ripple Three.js, gói gọn trong ảnh |
| Phân phối video | MP4 đơn / Vimeo | HLS thích ứng (kiểu Mux), rendition theo thiết bị |
Cross-device là một dự án riêng: điện thoại, tablet và desktop mỗi cái cần làm riêng, vì một chồng
ánh sáng blend-mode mượt trên GPU desktop có thể làm nóng chảy một điện thoại tầm trung. Các
guardrail — giới hạn số lớp video composite cùng lúc, hạ về một light plate tĩnh trên thiết bị yếu,
tôn trọng prefers-reduced-motion — là cùng kỷ luật ngân sách đằng sau bài
Core Web Vitals cho web nhiều chuyển động.
Vì sao đây mới là case study thật
Bài biên tập của Awwwards có ý nghĩa hơn một cái badge vì nó là biên tập — một phân tích được viết, được biên tập về tư duy, không phải một lá phiếu showcase một ngày. Thứ nó ghi lại là một triết lý tôi cố mang vào mọi bản build: làm cho nó cảm thấy đúng, và giấu kỹ phương pháp xuống dưới. Quyết định kỹ thuật hay nhất ở dự án này là chọn không viết một shader. Sự tiết chế chính là craft.
Nếu identity thương hiệu của bạn là fluid, xếp lớp, hay khó gói vào một cái nhãn — đó không phải vấn đề phải né, mà có thể là cả concept, nếu phần engineering đủ kỷ luật để gánh nó.
FAQ
Website thương hiệu biến đổi là gì?
Là website mà ngôn ngữ hình ảnh cố ý fluid thay vì cố định — identity thương hiệu được thể hiện qua chuyển động, transition và biến đổi thay vì một hệ logo-và-màu tĩnh. fromanother.love dùng ánh sáng chuyển động làm chính identity fluid đó.
Vì sao dùng video xếp lớp thay vì shader cho nền?
Với một look ánh sáng cinematic, grade màu bằng tay, footage thật đọc lên giàu hơn noise procedural, stream hiệu quả từ CDN, và gần như không tốn gì trên main thread. Một shader đẹp ngang thế sẽ tốn hơn để viết, chạy và art-direct. Shader xứng đáng ở các hiệu ứng thực sự tương tác, có tính hình học — như ripple của site.
Website fromanother được xây bằng gì?
Next.js và React, Prismic làm headless CMS, GSAP và Web Animations API cho motion, và Three.js với React Three Fiber cho tương tác ripple — cùng video-layering và blend mode gánh phần nền fluid chạy bằng ánh sáng.
Ai dựng fromanother.love?
fromanother dẫn dắt creative direction, identity và là người viết bài case study trên Awwwards; Hon Tran dựng nó với vai trò creative developer phụ trách front-end, motion, WebGL và tích hợp CMS.
Làm việc cùng tôi
Nếu bạn là thương hiệu, studio hay agency có một identity không chịu gói vào một look cố định — và muốn một site được engineer để gánh sự fluid đó ở 60fps — đó chính là việc tôi làm với vai trò creative developer.
- Xem thêm các dự án đã ship và đoạt giải trong kho dự án.
- Một creative developer mang lại gì cho bản build kiểu này: bắt đầu ở đây.
- Sẵn sàng trao đổi? Xem dịch vụ và các gói hợp tác hoặc let's talk →.
Viết bởi Hon Tran — creative developer, nhà sáng lập hontran.dev, và thành viên ban giám khảo Awwwards. Hơn 11 năm xây dựng trải nghiệm web đoạt giải, ưu tiên hiệu năng (GSAP, WebGL, Next.js) cho khách hàng toàn cầu. hontran.dev · Behance.