# Báo Cáo Khảo Sát & Thiết Kế Kiến Trúc: Hệ Thống Skill VFX, Asset Catalog & Chuẩn Hiệu Năng 120 FPS

> **Thực hiện bởi**: Subagent `teamwork_preview_explorer` (`explorer_survey_vfx_1`)  
> **Mục tiêu**: Khảo sát hiện trạng `vfx_renderer.js`, `combat_skills.js`, asset catalogs, nguy cơ vi phạm hygiene rules và thiết kế blueprint toàn diện cho hệ thống Skill VFX & UI/UX chuẩn Path of Exile 2 (PoE2).  
> **Ngân sách khung hình**: $120\text{ FPS}$ ProMotion ($8.33\text{ ms/frame}$), Zero GC Allocation trong hot loops.

---

## 1. Observation (Hiện Trạng Khảo Sát Thực Tế)

### 1.1. Hiện Trạng `vfx_renderer.js` (`client/webapp/js/engine/vfx_renderer.js`, 307 dòng)
* **Khả năng hiển thị hiện tại**:
  - `renderVfxProjectiles(ctx, dt)` (dòng 3-222): Xử lý 3 loại đạn đạo:
    1. *Liệt Huyết Cuồng Trảm* (`vfx_slashes`, dòng 6-72): Vòng cung xoay 2D (`ctx.arc`), vệt máu nhỏ (`sl.trailTimer >= 0.025`), phát nổ hạt máu khi trúng (`sl.progress >= 1.0`).
    2. *Hủ Cốt Hàn Độc* (`vfx_spikes`, dòng 75-141): 3 mũi tiêu xương (`ctx.moveTo`/`lineTo`), vệt khói độc/băng tuyết, vỡ hạt xương khi chạm mục tiêu.
    3. *Huyết Lôi Ma Kích* (`vfx_lightnings`, dòng 143-220): 7 đoạn zic-zac tiền tính toán, tia sét sky-bolt và vòng elip chấn động dưới đất (`ctx.ellipse`).
  - `renderVfxParticlesAndOverlay(ctx, dt, now)` (dòng 224-289): Vẽ mảng hạt `particles`, chữ số sát thương `damageTexts`, tàn tro bay `ashParticles`, và lớp vignette tối viền `vigGrad`.
  - `clearVfxProjectiles()` (dòng 291-305): Xóa các mảng global khi chuyển cảnh.
* **Cơ chế cấp phát bộ nhớ & Object Pooling**:
  - **HOÀN TOÀN KHÔNG CÓ OBJECT POOLING**:
    - Dòng 17-26, 38-47, 85-94, 107-116, 160-169: Cấp phát mới liên tục qua `particles.push({ x: ..., y: ..., vx: ..., col: ... })`. Mỗi hit nổ tạo từ 18-26 object mới.
    - Dòng 50, 119, 174, 231, 245: Dùng `splice(i, 1)` trực tiếp trong vòng lặp render trên mỗi frame khi hạt biến mất.
  - **Áp lực Garbage Collection (GC Thrashing)**: Ở 120 FPS, việc `push` và `splice` hàng ngàn object/giây gây ra các nhịp khựng (micro-stutter) do V8 Scavenger/Minor GC phải thu gom liên tục.
* **Hỗ trợ Screen Shake, Slashes/Trails, Shockwaves & Shaders**:
  - *Screen Shake*: Gọi `triggerScreenShake()` (định nghĩa tại `iso_math.js:242`), dịch chuyển canvas tại `canvas_renderer.js:275`.
  - *Slashes/Trails*: Chỉ là nét vẽ `ctx.arc()` đơn giản, vệt sau lưng dùng `player.ghostTrails.push()` vẽ lại sprite toàn thân làm mờ; KHÔNG có ribbon/strip mesh trail.
  - *Shockwaves*: Chỉ dùng nét vẽ elip `ctx.ellipse()`, KHÔNG có hiệu ứng khúc xạ (refraction) hay biến dạng bình thường (normal-mapped displacement).
  - *Shaders/WebGL*: $100\%$ Canvas 2D (`CanvasRenderingContext2D`), không có WebGL context hay GLSL shaders.
* **Lỗi Lệch Stack Canvas (Imbalance Bug)**:
  - Dòng 288 của `vfx_renderer.js` có `ctx.restore(); // Restore camera screen shake transformation`.
  - Tuy nhiên, trong `canvas_renderer.js:284` lại có thêm một lệnh `ctx.restore()` khác! Việc gọi `restore()` 2 lần cho 1 lần `save()` gây nguy cơ popping canvas context ngoài ý muốn.

### 1.2. Hiện Trạng `combat_skills.js` (`client/webapp/js/engine/combat_skills.js`, 489 dòng)
* **Nguy cơ vi phạm Hygiene Rule nghiêm trọng**: File hiện dài **489 dòng**, chỉ cách trần Hard Cap (500 dòng) đúng **11 dòng**.
* **Tập trung quá nhiều trách nhiệm trái ngược (High Coupling)**:
  - Khởi tạo hạt và đạn đạo (dòng 3-130).
  - Tính toán sát thương và kiểm tra đánh trúng mục tiêu `hitMonster` (dòng 140-226).
  - 3 hàm thi triển kỹ năng khởi đầu cứng (`doFire`, `doThunder`, `doFrost`, dòng 228-290).
  - Evasion `doDodge` với 0.25s i-frame (dòng 291-306).
  - Bắt phím cứng (Q, E, R, Space, Tab, dòng 327-342) và gán trực tiếp vào `#skill-fire`, `#skill-thunder`, `#skill-frost`.
  - Cơ chế tương tác cổng dịch chuyển Hideout & Vạn Giới Giới Môn (dòng 344-474) nhồi nhét chung trong file combat!

### 1.3. Khảo Sát Hệ Thống Kỹ Năng FreeExile (Canonical Skills)
* **Trong CSDL & Server Logic** (`server/world/martial_catalog.py`, `proto/combat.proto`, `game_design_matrix_seeder.py`):
  Đã chuẩn hóa **10 Chân Võ Đan (Active Martial Skills)** đại diện cho 5 Hệ Ngũ Hành và 5 Tông Phái:

| ID | Tên Chiêu Thức | Ngũ Hành | Môn Phái | Vũ Khí Yêu Cầu | Cơ Chế Cốt Lõi |
| :--- | :--- | :--- | :--- | :--- | :--- |
| **1001** | Cửu Tiêu Lôi Kiếm | Kim (Lôi) | Thanh Phong Kiếm Tông | Kiếm (Sword) | Phóng cự kiếm lôi quang xuyên thấu, sát thương đơn mục tiêu cực đại (+180%). |
| **1002** | Thanh Phong Vạn Kiếm Vũ | Kim | Thanh Phong Kiếm Tông | Kiếm (Sword) | Phóng 8 kiếm khí hình nón quét góc 120°, channeling duy trì. |
| **1003** | U Minh Huyết Độc Châm | Mộc (Độc) | U Minh Độc Y | Cung/Ám khí (Bow/Dagger) | Ghim châm độc rút máu 150%/s trong 4s, sát thương va chạm = 0, lây lan khi quái chết. |
| **1004** | Thiên Ma Bộc Độc Kình | Mộc (Độc) | U Minh Độc Y | Bất kỳ (Any) | Kích nổ toàn bộ độc tố trong bán kính 5m (x2.5 sát thương), tiêu hao 15% HP người chơi. |
| **1005** | Băng Phách Hàn Quang Trận | Thủy (Băng)| Hàn Băng Thần Điện | Trượng/Thương (Staff/Spear)| Đóng băng mặt đất 6m trong 3s, tạo khiên Hộ Thể 25%, không thể bạo kích. |
| **1006** | Băng Tiễn Xuyên Tâm | Thủy (Băng)| Hàn Băng Thần Điện | Trượng/Cung (Staff/Bow) | Bắn băng tiễn tầm xa 16m xuyên mục tiêu, nổ mảnh vụn, cự ly tối thiểu 3.5m. |
| **1007** | Liệt Hỏa Toàn Phong Trảm | Hỏa (Diễm) | Liệt Diễm Cuồng Đao | Đao/Rìu (Blade/Axe) | Xoay tròn 360° liên tục như bão lửa, vừa chạy vừa chém, miễn nhiễm choáng. |
| **1008** | Liệt Diễm Bộc Khí Trảm | Hỏa (Diễm) | Liệt Diễm Cuồng Đao | Đao (Blade) | Bổ dọc chẻ đôi mặt đất (+250%), tạo vệt dung nham thiêu đốt, khựng 750ms. |
| **1009** | Kim Cang Trụy Địa Chấn | Thổ (Nham) | Kim Cang Tông | Trượng/Chùy (Staff/Mace) | Nhảy giáng mạnh xuống đất tạo chấn động 5m, choáng 2s, tăng 40% giáp. |
| **1010** | Kim Cang Bất Hoại Thể | Thổ (Hộ) | Kim Cang Tông | Tay không/Khiên (Unarmed) | Kích hoạt kim thân giảm 75% sát thương nhận vào, phản đòn 40%, khóa chân 4s. |

* **Tài Nguyên Sẵn Có Nhưng Chưa Được Đấu Nối**:
  1. `client/webapp/assets/skills/martial_skills_atlas.png` ($1.9\text{ MB}$, $1024 \times 1024$): Sprite Atlas chứa icon chuẩn của toàn bộ 10 chiêu thức trên.
  2. `client/webapp/assets/skills/martial_skills_metadata.json`: Tọa độ UV và `pixel_rect` chính xác ($256 \times 256$ mỗi tile) của 10 kỹ năng.
  3. `client/webapp/assets/skills/elemental_particles.metal`: Metal compute shader cho 5 hệ hạt Kim (Lôi zic-zac), Mộc (Độc khói khuếch tán), Thủy (Băng rơi tinh thể), Hỏa (Lửa bốc cuộn), Thổ (Sỏi đá chấn động).
  4. `client/webapp/assets/savage_vfx/savage_vfx_atlas.png` & `savage_vfx_atlas_normal.png`: Atlas 16 frame hoạt ảnh trảm kích, huyết lôi, hủ cốt và thân pháp kèm Normal Map.

### 1.4. Tình Trạng Tệp `telegraph_renderer.js`
* File `client/webapp/js/engine/telegraph_renderer.js` **CHƯA TỒN TẠI** trong thư mục mã nguồn. Toàn bộ cơ chế windup/telegraph hiện tại chỉ đang thể hiện qua timer logic trong `monster_system.js` mà chưa có renderer trực quan trên mặt đất.

### 1.5. Hiện Trạng Giao Diện HUD & Stylesheets
* `client/webapp/css/`: Chỉ có `main.css` (72 dòng) và `trailer.css` (293 dòng). Hoàn toàn chưa có stylesheet chuyên biệt cho HUD kỹ năng (`hud_skills.css`).
* `index.html`: Thanh kỹ năng ở góc phải dưới (dòng 103-111) dùng các nút tròn tĩnh cứng, thiếu hoạt ảnh quét hồi chiêu (cooldown sweep), thiếu viền sáng sẵn sàng (ready glow), và chưa có cặp ngọc Huyết / Khí (PoE2 Health & Mana Orbs).

---

## 2. Logic Chain (Chuỗi Suy Luận Kỹ Thuật)

```
[Observation 1.1: particles.push & splice liên tục]
       │
       ▼ (Gây GC pauses 10-25ms định kỳ -> phá vỡ trần 8.33ms của 120 FPS)
[Logic Step 1: Bắt buộc triển khai Pre-allocated Object Pool & Swap-and-Pop]
       │
       ├────────────────────────────────────────────────────────┐
       ▼                                                        ▼
[Observation 1.2: combat_skills.js = 489 dòng]    [Observation 1.3: Có sẵn Atlas 10 Skill]
       │                                                        │
       ▼ (Nguy cơ vi phạm Hard Cap 500 dòng)                   ▼ (Chưa kết nối vào webapp)
[Logic Step 2: Tách module theo Tam Phân Lập]      [Logic Step 3: Xây dựng Dynamic Catalog]
       │                                                        │
       ├─ Tách data -> skill_catalog.js (< 700 dòng)            └─ Load martial_skills_atlas.png
       ├─ Tách pool -> vfx_pool.js (< 350 dòng)                 └─ Render icon & VFX đa tầng
       ├─ Tách telegraph -> telegraph_renderer.js (< 350 dòng)
       └─ combat_skills.js giảm về ~260 dòng sạch sẽ
```

1. **Từ Quan sát 1.1**: Việc khởi tạo object mới trong các hàm `spawnParticles`, `spawnInfernalSlash`, `spawnLightningStrike` tạo ra hàng nghìn allocs rải rác trên heap. Khi thu gom rác, browser sẽ drop frame. **Suy ra**: Cần một module `vfx_pool.js` cấp phát mảng tĩnh (`Float32Array` hoặc mảng object cố định 512 hạt) với cơ chế tái sử dụng tái kích hoạt trong $O(1)$ mà không bao giờ gọi `new` hay `splice()`.
2. **Từ Quan sát 1.2 & Hygiene Gate**: `combat_skills.js` đang gánh cả input, portal interaction, damage logic và particle spawn (489 dòng). Nếu triển khai thêm VFX của 10 kỹ năng mới vào file này, nó sẽ ngay lập tức vượt trần 500 dòng và làm gãy CI/CD. **Suy ra**: Cần tái cấu trúc bóc tách dứt điểm các mảng dữ liệu sang `js/data/skill_catalog.js` và logic hồ hạt sang `js/engine/vfx_pool.js`.
3. **Từ Quan sát 1.3**: Dự án đã có sẵn các asset atlas cực kỳ chất lượng (`martial_skills_atlas.png`, `savage_vfx_atlas.png`) nhưng chưa được nạp vào vòng lặp game. **Suy ra**: Thiết kế kiến trúc VFX Renderer theo mô hình 4 tầng (Anticipation -> Projectile/Trajectory -> Impact Burst -> Lingering Surface Scars) sử dụng trực tiếp các atlas này kết hợp kỹ thuật Canvas Composite modes.
4. **Từ Quan sát 1.4**: Yêu cầu PoE2 Visceral Combat đòi hỏi người chơi có thể né chiêu của Boss bằng Huyễn Ảnh Bộ. Muốn làm được điều này, chiêu thức của Boss và Monster bắt buộc phải có visual telegraph (vùng nón, vòng tròn đỏ cam hiển thị tiến độ tụ khí). **Suy ra**: Cần khởi tạo mới `client/webapp/js/engine/telegraph_renderer.js` chuyên biệt hóa việc vẽ telegraph dưới chân quái trước khi tung đòn.
5. **Từ Quan sát 1.5**: Giao diện cần chuẩn hóa cặp ngọc Huyết / Khí (Orbs) và thanh chiêu thức có lớp phủ hồi chiêu (Radial SVG sweep). **Suy ra**: Tạo `client/webapp/css/hud_skills.css` tuân thủ Soft Cap $\le 350$ dòng.

---

## 3. Caveats (Các Điểm Giới Hạn & Giả Định)

1. **Khả năng tương thích phần cứng**: Metal Shaders (`elemental_particles.metal`) chỉ biên dịch trên Apple Silicon / WebGPU (Safari/macOS/iOS). Do đó, trên WebApp Canvas tiêu chuẩn, toàn bộ logic hạt ngũ hành phải có bộ mô phỏng JavaScript/Canvas 2D tương đương (Fallback Renderer) với cùng công thức toán học.
2. **Kích thước Asset Atlas**: `martial_skills_atlas.png` ($1.9\text{ MB}$) cần được nạp bất đồng bộ qua `Image()` với sự kiện `onload` an toàn để không gây gián đoạn khung hình đầu tiên khi vào game.
3. **Nguyên tắc Read-Only của Điều Tra**: Trong vai trò Explorer, subagent không chỉnh sửa trực tiếp mã nguồn của engine, chỉ cung cấp blueprint, bản thiết kế giao diện và đoạn mã mẫu để implementer triển khai.

---

## 4. Conclusion & Blueprint Thiết Kế Toàn Diện

### 4.1. Kiến Trúc Phân Tách Module & Giới Hạn Dòng (Zero-Violation Structure)

```
client/webapp/
├── css/
│   ├── main.css                   (72 dòng - Đã có)
│   └── hud_skills.css             (MỚI - ~220 dòng <= 350 Soft Cap: Ngọc Huyết/Khí, Skill Slot, Cooldown Sweep)
├── assets/
│   ├── skills/                    (Đã có metadata, atlas 1024x1024, metal shader)
│   └── savage_vfx/                (Đã có atlas 512x512 và normal maps)
└── js/
    ├── data/
    │   ├── skill_catalog.js       (MỚI - ~380 dòng <= 700 Catalog Soft Cap: Định nghĩa 10 Chân Võ Đan & Icons)
    │   └── vfx_presets_catalog.js (MỚI - ~250 dòng <= 700 Catalog Soft Cap: Preset hạt ngũ hành & màu sắc)
    ├── engine/
    │   ├── vfx_pool.js            (MỚI - ~240 dòng <= 350 Code Soft Cap: Static Object Pooling, Zero Alloc)
    │   ├── telegraph_renderer.js  (MỚI - ~190 dòng <= 350 Code Soft Cap: Vùng cảnh báo nón/tròn/tia PoE2)
    │   ├── vfx_renderer.js        (Refactor sửa lỗi restore & tích hợp atlas - ~280 dòng <= 350 Soft Cap)
    │   └── combat_skills.js       (Refactor giảm tải, chuyển portal về ui/ - ~260 dòng <= 350 Soft Cap)
    └── ui/
        └── skill_bar_controller.js(MỚI - ~210 dòng <= 350 Code Soft Cap: Quản lý gán slot, phím tắt, Cooldown)
```

### 4.2. Blueprint Module 1: `vfx_pool.js` (Hồ Tái Sử Dụng Đối Tượng 120 FPS)
* **Nguyên lý $O(1)$ Swap-and-Pop**:

```javascript
// client/webapp/js/engine/vfx_pool.js (Design Spec)
export class VfxPoolManager {
  constructor(maxParticles = 512, maxProjectiles = 64) {
    this.maxParticles = maxParticles;
    this.particles = new Array(maxParticles);
    for (let i = 0; i < maxParticles; i++) {
      this.particles[i] = {
        active: false, x: 0, y: 0, vx: 0, vy: 0,
        color: '#ffffff', alpha: 1.0, decay: 0.03, radius: 2.0,
        elementType: 0, life: 0, maxLife: 1.0, atlasFrame: null
      };
    }
    this.activeParticleCount = 0;
  }

  acquireParticle(initProps) {
    if (this.activeParticleCount >= this.maxParticles) return null; // Drop gracefully
    const p = this.particles[this.activeParticleCount];
    Object.assign(p, initProps);
    p.active = true;
    p.life = 0;
    this.activeParticleCount++;
    return p;
  }

  update(dt) {
    for (let i = this.activeParticleCount - 1; i >= 0; i--) {
      const p = this.particles[i];
      p.life += dt;
      p.x += p.vx;
      p.y += p.vy;
      p.alpha -= p.decay;

      if (p.alpha <= 0 || p.life >= p.maxLife) {
        p.active = false;
        // Swap-and-Pop in O(1): Hoán đổi phần tử chết với phần tử cuối cùng đang active
        this.activeParticleCount--;
        const lastActive = this.particles[this.activeParticleCount];
        this.particles[i] = lastActive;
        this.particles[this.activeParticleCount] = p;
      }
    }
  }
}
```

### 4.3. Blueprint Module 2: `telegraph_renderer.js` (Hệ Thống Báo Trước Đòn Đánh Chuẩn PoE2)
* **Thông số hỗ trợ**:
  - Dạng vòng tròn bán kính tỏa ra (`circle`): Thể hiện phạm vi nổ dậm đất của boss hoặc kỹ năng diện rộng.
  - Dạng hình nón góc quét (`cone`): Thể hiện nhát chém quét ngang 90°-120° của đại đao hoặc quái vật.
  - Dạng đường thẳng chữ nhật (`rect_beam`): Thể hiện tia sét, băng tiễn hoặc đòn lao tới.
  - Có vòng lồng màu cam/đỏ (`#ea580c` -> `#dc2626`) tăng dần độ đậm theo tiến độ wind-up ($0.0 \rightarrow 1.0$), cho phép người chơi nhận diện thời khắc bấm Space (Huyễn Ảnh Bộ) để lấy i-frame.

```javascript
// client/webapp/js/engine/telegraph_renderer.js (Interface Spec)
export const TelegraphRenderer = {
  activeTelegraphs: [],

  addTelegraph(type, originWx, originWy, duration, params = {}) {
    this.activeTelegraphs.push({
      type, // 'cone', 'circle', 'line'
      wx: originWx, wy: originWy,
      progress: 0, duration,
      radius: params.radius || 4.0,
      angle: params.angle || 0,
      spread: params.spread || Math.PI * 0.5,
      color: params.color || 'rgba(239, 68, 68, 0.45)',
      fillProgressColor: params.fillColor || 'rgba(220, 38, 38, 0.85)'
    });
  },

  render(ctx, dt) {
    // Vẽ trực tiếp lên mặt đất ở tầng dưới nhân vật (renderWorldEnvironment)
    // Chuyển tọa độ worldToIso và vẽ cung tròn 2.5D có tỷ lệ trục y = x * 0.5
  }
};
```

### 4.4. Blueprint Module 3: `skill_catalog.js` & Giao Thức Đa Tầng VFX 10 Kỹ Năng
Mỗi kỹ năng trong số 10 Chân Võ Đan được định nghĩa cấu trúc 4 tầng:
1. **Khởi động (Anticipation / Windup)**: Vòng sáng nén dưới chân, hạt tụ khí xoáy vào vũ khí, thời gian khóa cử động.
2. **Quỹ đạo (Trajectory / Execution)**: Sprite frame lấy từ `martial_skills_atlas.png` hoặc `savage_vfx_atlas.png`, kèm vệt hạt kéo dài.
3. **Va chạm (Impact Frame)**: Hit-stop micro ($2\text{ frames} \approx 16\text{ms}$ dừng hình), hạt nổ ngũ hành tương ứng (Lôi: tia chớp phân nhánh; Hỏa: mảnh tàn tro đỏ cam; Thủy: gai băng vỡ vụn; Mộc: khói độc bung tỏa; Thổ: chấn động nứt đất), kèm âm thanh và rung màn hình thích ứng.
4. **Hậu quả bề mặt (Ground Lingering)**: Vệt rạch đất cháy xém, băng găm mặt đất hoặc ao độc tồn tại $1.5 - 3.0\text{s}$.

### 4.5. Blueprint Module 4: Giao Diện HUD Chuẩn ARPG Hiện Đại (`hud_skills.css`)
* **Health Orb (Ngọc Huyết Tế Cốt)**: Bố trí góc dưới bên trái, dạng cầu thủy tinh chứa dung dịch máu sóng sánh (dùng gradient đa tầng và hiệu ứng bóng phản chiếu specular highlight).
* **Mana / Energy Orb (Ngọc Chân Khí)**: Bố trí bên cạnh hoặc lồng ghép tinh tế với thanh năng lượng xanh lam ma mị.
* **Skill Slots & Cooldown Sweep**:
  - 5 slot phím tắt: Q (Chiêu 1), W (Chiêu 2), E (Chiêu 3), R (Chiêu Tối Thượng), Space (Cuồng Dã Báo Bộ).
  - Hoạt ảnh hồi chiêu dùng SVG Mask / `conic-gradient` tạo lớp phủ bóng tối quét ngược chiều kim đồng hồ từ $360^\circ \rightarrow 0^\circ$.
  - Khi hồi chiêu kết thúc, kích hoạt hiệu ứng chớp sáng vàng viền (`ready-flash` keyframe animation) và phản hồi rung xúc giác haptic nhẹ.

---

## 5. Verification Method (Phương Pháp Kiểm Chứng Độc Lập)

Sau khi đội ngũ thi công tiến hành triển khai các module mã nguồn theo thiết kế, quá trình nghiệm thu được thực hiện theo 4 bước độc lập:

1. **Kiểm tra độ dài & vệ sinh mã nguồn (Hygiene Gate)**:
   ```bash
   python tools/lint/check_code_and_doc_hygiene.py --strict
   ```
   *Điều kiện đạt*: Toàn bộ file mới tạo (`skill_catalog.js`, `vfx_pool.js`, `telegraph_renderer.js`, `hud_skills.css`) phải $\le 350$ dòng (Soft Cap) và không file nào vượt quá Hard Cap ($500$ dòng cho Code, $1000$ dòng cho Catalog).

2. **Kiểm tra cấp phát bộ nhớ & Ngân sách 120 FPS qua Chrome DevTools MCP**:
   - Sử dụng tool `performance_start_trace` và `performance_stop_trace` trên trình duyệt mô phỏng `client/webapp/index.html`.
   - Spam combo liên tục cả 4 phím Q, E, R, Space vào Mộc Nhân Thử Chiêu (`dummy_primal_shrine`).
   - Kiểm tra biểu đồ Heap Allocation: Tốc độ cấp phát bộ nhớ mới trong hot loop phải tiệm cận $0\text{ MB/s}$ (Zero Memory Allocation). Không có răng cưa Garbage Collection Major GC.
   - FPS đo tại phần tử `#hud-fps` duy trì ổn định $\ge 115 - 120\text{ FPS}$ (trên màn hình 120Hz) và $\ge 60\text{ FPS}$ (trên màn hình 60Hz tiêu chuẩn).

3. **Kiểm tra tính toàn vẹn 10 Kỹ Năng & Visual Telegraph**:
   - Mở Console trình duyệt, xác nhận không có bất kỳ exception nào từ `vfx_renderer.js` hay `telegraph_renderer.js`.
   - Kích hoạt kỹ năng của Boss hoặc Elite, xác minh vòng tròn/vùng nón màu cam hiển thị rõ trên mặt đất trước khi đòn đánh giáng xuống.
   - Thực hiện né tránh bằng Huyễn Ảnh Bộ (Space) đúng thời điểm xuất hiện dòng chữ `NÉ ĐÒN! (i-frame)` màu xanh lơ mà không bị trừ máu.

4. **Kiểm tra hiển thị giao diện HUD**:
   - Kiểm tra hiển thị của Ngọc Huyết, Ngọc Khí và thanh kỹ năng trên cả chế độ iPhone 15 Pro (`#mode-iphone`) và toàn màn hình (`#mode-fullscreen`).
   - Cooldown sweep hiển thị mượt mà trên từng nút chiêu thức.
