707eb0f5c1
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6.5 KiB
6.5 KiB
Thiết kế: Tối ưu hiệu năng web phy-vr360
- Ngày: 2026-06-25
- Trạng thái: Đã duyệt thiết kế, chờ lập kế hoạch triển khai
- Chiến lược: Hướng A — tối ưu theo giai đoạn, ưu tiên việc rẻ–lợi-cao
- Ràng buộc người dùng: Giữ thẩm mỹ tổng thể nhưng bỏ lớp thừa; được phép nén cả ảnh và model 3D.
1. Vấn đề
Web khi chạy làm laptop nóng/quạt rú, cuộn giật, trải nghiệm không mượt. Cảm nhận là toàn bộ site đều nặng, không khu trú một chỗ.
2. Nguyên nhân gốc (đã phân tích)
Nghiêm trọng
- Trang chủ chồng 3 ngữ cảnh WebGL chạy liên tục —
hero-shader-background.tsx:- 2×
MeshGradient(shader GPU paper-design) animation vô hạn 60fps. - 1×
HeroPanoramaBackground(hero-panorama-background.tsx): WebGLRenderer three.js, quả cầu xoay,requestAnimationFramerender vô điều kiện, tải ảnh panorama vài MB chỉ để làm nền mờ 58%. mix-blend-mode: soft-light+ filter SVGfeTurbulence.- Không có
IntersectionObserver/visibilitychange→ chạy cả khi cuộn khỏi vùng nhìn hoặc đổi tab.
- 2×
- Ảnh panorama nặng, không tối ưu — 26 ảnh JPG 6144×3072, 2–4MB/ảnh (tổng ~70MB), nạp thẳng làm texture three.js ở độ phân giải gốc. Cache
panoramaTextureCache(VirtualTour.tsx:214) giữ toàn bộ texture vĩnh viễn → tràn VRAM trên máy card tích hợp → thrashing/khựng.next.config.tsrỗng. - Model 3D
.glbkhổng lồ —chuong-2.glb40MB,chuong-1.glb27MB → đơ tab khi parse.AntiquityViewer.tsxrender mọi frame vô điều kiện, pixelRatio tới 2.
Phụ (tích lũy)
- CSS animation luôn-bật + hiệu ứng nặng (
globals.css): nềnbodychồng 4 lớp gradient +body::aftermix-blend-mode: multiplyfull màn hình;public-ambient-pan18s vô hạn; gradient-text flow; logo/CTA "breathe"; header "glint"; lớp.site-grainnhiễu SVG full màn hình;backdrop-filter: blur(18px)trên mọi.public-panel/.public-card+will-change: transform(ép tạo layer, tốn bộ nhớ). - Điểm tốt sẵn có: Tour viewer chính (
VirtualTour.tsx:1502) đã render theo nhu cầu (needsRenderRef) — giữ và nhân rộng mô hình này.
3. Phạm vi
Trong phạm vi: trang chủ + các trang công khai, tour viewer 360, viewer cổ vật 3D, pipeline tài nguyên (ảnh + model), cấu hình build, ngân sách CSS.
Ngoài phạm vi: thay đổi nội dung/bố cục lớn, thêm tính năng mới, thiết kế lại giao diện.
4. Giải pháp theo giai đoạn
Giai đoạn 1 — Chặn việc chạy nền vô ích (đòn bẩy lớn nhất, rủi ro thấp)
- Hero: thay
HeroPanoramaBackground(canvas three.js xoay) bằng ảnh tĩnh đã tối ưu (next/image hoặc CSS background) → loại bỏ 1 ngữ cảnh WebGL + texture vài MB. Giảm 2 → 1MeshGradient; bỏmix-blend-mode: soft-light; gỡ filter SVGfeTurbulencenếu không cần. - Gate mọi WebGL/animation nền bằng
IntersectionObserver+document.visibilitychange: ngoài màn hình hoặc đổi tab → dừngrequestAnimationFrame/setAnimationLoop. Áp dụng cho hero (nếu còn shader) vàAntiquityViewer. - AntiquityViewer: chuyển sang render theo nhu cầu (theo mô hình tour viewer) — chỉ vẽ khi
controlsđổi hoặc đang tự xoay; pixelRatio tối đa 1.5; dừng khi ngoài màn hình; đảm bảo chỉ một viewer hoạt động tại một thời điểm (lazy-mount, không khởi tạo tất cả.glbcùng lúc).
Giai đoạn 2 — Pipeline tài nguyên
- Ảnh panorama: thêm script Node (
sharp) tạo bản tối ưu:- Resize tối đa 4096px chiều rộng (giữ tỉ lệ 2:1), xuất WebP chất lượng ~80 (cân nhắc AVIF). Mục tiêu giảm 70–85% dung lượng.
- Tour viewer nạp bản
.webp; giữ LQIP blur-up sẵn có (chua-thai-lac.lqip.ts).
- Model 3D: dùng
gltf-transform(Draco/meshopt + nén texture/resize) → 40MB ⟶ ước tính 3–8MB. ThêmDRACOLoader/meshopt decoder vàoAntiquityViewer; lazy-load model. - Cache texture có giới hạn (LRU): chỉ giữ cảnh hiện tại + lân cận, dispose phần xa → tránh tràn VRAM. Cân nhắc tắt mipmap cho ảnh cầu (giảm chi phí upload), kiểm chứng chất lượng.
Giai đoạn 3 — Ngân sách hiệu ứng CSS
- Giảm
backdrop-filter: blur: hạ bán kính hoặc thay bằng nền bán trong suốt cho phần tử phổ biến; bỏwill-change: transformở phần tử luôn hiển thị (chỉ đặt khi cần, ví dụ lúc hover). - Tắt bớt animation vô hạn ít giá trị:
public-ambient-pan, gradient-text flow, logo/CTA "breathe", header glint,.site-grain. Giữ hiệu ứng xuất hiện-khi-cuộn (chạy 1 lần) và marquee. - Gọn lại lớp gradient nền
body/public-page.
Giai đoạn 4 — Chia nhỏ bundle & tải
dynamic importcác thành phần nặng three.js (tour viewer,AntiquityViewer) để bundle chính nhẹ; đảm bảoframer-motion/lottie-reactchỉ tải nơi cần.- Cấu hình
next.config.ts: bậtimages(AVIF/WebP,deviceSizes) và tối ưu build hợp lệ cho Next 16.
5. Cách đo thành công (nghiệm thu)
- Trang chủ lúc rảnh ≈ 0% GPU (không còn rAF chạy ngầm); cuộn ~60fps; không còn quạt rú.
- Số ngữ cảnh WebGL trên trang chủ: 3 → 0–1.
- Dung lượng tải trang giảm rõ (ảnh panorama & model 3D).
- Lighthouse Performance tăng; không hồi quy giao diện nhìn thấy được.
6. Rủi ro & lưu ý
- Next.js 16 bản đã chỉnh sửa (theo
AGENTS.md): trước khi sửanext.config/dynamic-import phải đọc tài liệu trongnode_modules/next/dist/docs/. - Nén ảnh/model có thể đổi nhẹ chất lượng → kiểm chứng bằng mắt sau mỗi bước; giữ file gốc (không ghi đè, xuất ra thư mục/định dạng mới).
- Việc gate animation phải dọn dẹp listener đúng cách để tránh rò rỉ bộ nhớ.
7. Nguyên tắc thực thi
- Làm tuần tự theo giai đoạn; đo lại sau mỗi giai đoạn trước khi sang bước kế tiếp.
- Mỗi thay đổi giữ đúng pattern/định dạng code hiện có của dự án.