---
name: design-system
description: Reverse-engineer the visual design system of a reference website (colors, typography, spacing, shadows, component patterns, page anatomy) from real computed styles and DOM, then produce a portable DESIGN_SYSTEM.md plus a single-file demo.html that closely follows the measured style without copying the source's brand/content. Use when the user gives a reference URL and asks to "nhái style", "tạo design system", "làm design system giống trang X", or "demo HTML y chang [site]".
---

# Design System from a Reference Site

Bản public miễn phí của Web1trang. Hướng dẫn AI trích pattern và token từ website tham khảo, tạo `DESIGN_SYSTEM.md` và `demo.html` cho dự án của bạn. Không kèm sẵn kết quả trích xuất. Cần công cụ AI có quyền đọc/ghi file và browser automation. Các API browser/read dưới đây là ví dụ minh hoạ; điều chỉnh theo công cụ thực tế, giữ nguyên yêu cầu đo và kiểm tra.

## Nguyên tắc cứng

1. **Không đoán giá trị.** Mọi hex màu, px, font-weight, shadow phải lấy từ `getComputedStyle` thật hoặc từ class/HTML thật của trang, không bịa theo cảm giác.
2. **Không copy nguyên nội dung/asset của nguồn.** Lấy đúng *pattern* (cấu trúc, class, token), nhưng text/logo/ảnh trong `demo.html` phải là placeholder generic ("YourBrand", "Brand A/B/C", slot comment `<!-- slot: ... -->`) để dùng lại được cho dự án bất kỳ — đây là lý do tách riêng `DESIGN_SYSTEM.md` (tài liệu tái dùng) khỏi bản demo cụ thể.
3. **`demo.html` phải tự chạy được**, không build step, không phụ thuộc Tailwind CDN JIT cho utility tuỳ biến (`shadow-button`, `bg-cells`, `animate-pixel-blink`...) — viết thẳng CSS thuần với đúng giá trị đã trích xuất, để đảm bảo render đúng 1-lần-ăn-ngay, không phụ thuộc mạng/JIT compile không chắc chắn.
4. **Verify bằng browser thật**, không chỉ đọc code — chụp screenshot, bật thử dark mode, click thử nút, xác nhận không có console error.

## Quy trình

### 1. Khảo sát trang tham khảo bằng browser eval
```js
const tab = await browser.open({ name: "ref", url: "<URL>", viewport: { width: 1440, height: 900 } });
```
- Chụp `fullPage` screenshot ngay — nếu thấy nhiều khoảng trắng bất thường giữa các block, đó là dấu hiệu nội dung dùng `IntersectionObserver` reveal-on-scroll (chưa trigger). **Fix**: cuộn thật qua từng đoạn ~200-300px với `page.evaluate(() => window.scrollTo(...))` + delay, rồi mới chụp lại; hoặc chụp viewport-by-viewport (không `fullPage`) tại từng mốc scroll để bắt đúng trạng thái đã reveal.
- Nếu trang có nút đổi theme (tìm qua `tab.observe()` role=button name chứa "sáng/tối", "dark/light", icon moon/sun): bấm thử, chụp lại để có cả 2 bộ màu.

### 2. Trích token màu/typography/shadow qua computed styles
Dump toàn bộ CSS custom properties một lần (nhanh hơn đoán tên biến):
```js
await tab.run(async ({ page }) => page.evaluate(() => {
  const root = getComputedStyle(document.documentElement);
  const out = {};
  for (let i = 0; i < root.length; i++) {
    const n = root[i];
    if (n.startsWith('--')) out[n] = root.getPropertyValue(n).trim();
  }
  return out;
}));
```
- Lọc nhóm cần: `--color-*`, `--shadow-*`, `--radius-*`, `--font-*`, `--text-*`.
- Nếu trang không dùng CSS vars (style inline/Tailwind runtime), lấy trực tiếp qua `getComputedStyle(element)` trên các selector mẫu: `h1`, `h2`, `p`, nút CTA (tìm theo `background-color` đặc trưng), nav, `code`/`pre`.
- Lặp lại bước này sau khi bật dark mode để có bảng màu thứ 2.

### 3. Trích cấu trúc HTML/class thật (không đoán class Tailwind)
Trang production thường minify thành **1 dòng HTML cực dài** — công cụ đọc file sẽ cắt ở ~768 ký tự/dòng. Cách lách:
```bash
node -e "fetch('<URL>').then(r=>r.text()).then(t=>require('fs').writeFileSync('ref.html', t))"
node -e "
const t=require('fs').readFileSync('ref.html','utf8');
const idx = t.indexOf('<chuỗi text độc nhất gần khối cần xem>');
require('fs').writeFileSync('slice.html', t.slice(idx-2500, idx+2500));
"
```
Rồi đọc file slice bằng `read` với hậu tố `:raw` (bỏ qua giới hạn dòng, lấy nguyên văn):
```
read path="slice.html:raw"
```
Lặp lại `indexOf` bằng các cụm text độc nhất (heading, nút, badge) để đi lần lượt qua: header/nav, hero, các section chính, card/grid, footer. Ghi chú lại **chính xác** class list, thứ tự thẻ, kỹ thuật dựng (vd: `display:grid;gap:1px;background:border-color` + `li{background:page-color}` để tạo đường viền hairline giữa các ô mà không cần border riêng).

### 4. Viết `DESIGN_SYSTEM.md`
Cấu trúc tối thiểu:
1. Color tokens — bảng light + bảng dark (token name | hex/value | dùng cho).
2. Typography — font family (heading/body/mono), bảng size/line-height/tracking/weight theo từng cấp heading & breakpoint.
3. Spacing & layout grid — container max-width, kỹ thuật viền/khoảng cách đặc trưng (nếu có, ví dụ: viền kẻ cột xuyên trang, dấu góc, hairline grid).
4. Shadow tokens — giá trị `box-shadow` đầy đủ cho từng cấp (card/float/button...), ghi rõ khác biệt light/dark nếu có.
5. Thành phần (component recipes) — mỗi component: cấu trúc, class, trạng thái hover/active, biến thể.
6. Bố cục trang (page anatomy) — liệt kê tuần tự các section và nội dung từng section.
7. Nguyên tắc áp dụng — 4-6 quy tắc rút ra để người khác tự mở rộng đúng phong cách mà không cần đọc lại code gốc.

Mở đầu file phải nêu rõ: đây là **tài liệu dùng chung, không gắn thương hiệu cụ thể**, nguồn tham khảo phong cách là gì, mọi tên/nội dung mẫu trong demo chỉ là placeholder.

### 5. Viết `demo.html` (single file)
- `<style>` inline: `:root{--color-*...}` + `html.dark{...override...}`, rồi toàn bộ class dựng tay theo đúng section ở bước 3 (giữ tên pattern tương tự để dễ đối chiếu, vd `.card-grid`, `.section-label`, `.corner`).
- Google Fonts link nếu cần đúng font (Inter, JetBrains Mono, v.v.) — khai báo `font-family` có fallback.
- Nội dung: **thay bằng placeholder generic** (brand "YourBrand", feature card "Tính năng của bạn", logo marquee "Brand A/B/C..."), giữ nguyên số lượng khối/layout để chứng minh style khớp mà không redistribute nội dung/asset gốc.
- JS thuần (không framework): dark-mode toggle (`classList.toggle('dark')` + `localStorage`), copy-to-clipboard cho code block, `IntersectionObserver` cho hiệu ứng reveal-on-scroll nếu bản gốc có, segmented control decorative nếu có.

### 6. Verify bằng browser thật
```js
const tab = await browser.open({ name: "demo", url: "file:///<path>/demo.html", viewport: {...} });
```
- Chụp `fullPage` sau khi cuộn qua hết trang (kích hoạt `.reveal`).
- Zoom từng section quan trọng (viewport screenshot, không fullPage) để so khớp chi tiết với screenshot bước 1.
- Bấm thử theme toggle → chụp lại, so với bảng màu dark đã trích ở bước 2.
- Bấm thử nút copy → kiểm tra class/feedback đổi trạng thái đúng qua `page.evaluate`.
- Check `tab.errors()` — phải rỗng.

### 7. Dọn dẹp
Xoá mọi file trung gian dùng để trích xuất (`ref.html`, `slice*.html`, `part*.html`...). Thư mục output cuối chỉ còn `DESIGN_SYSTEM.md` + `demo.html` (và asset phụ nếu có).

## Lỗi thường gặp (đã gặp thực tế, tránh lặp lại)
- **Tin vào `fullPage` screenshot chụp ngay sau khi mở trang** → sai nếu trang dùng reveal-on-scroll; phải cuộn qua trước.
- **Đọc raw HTML minify bằng `bash`/`read` thường** → bị cắt ở 768 ký tự vì cả file là 1 dòng; phải `node -e` cắt lát theo `indexOf` rồi đọc `:raw`.
- **Tin Tailwind Play CDN dựng đúng utility tuỳ biến** (`shadow-button`, `mask-fade-center`...) → không chắc chắn; viết CSS thuần với giá trị đã đo để chủ động 100%.
- **Copy logo/ảnh nhị phân hoặc nguyên văn câu chữ marketing của nguồn** → tránh; dùng placeholder generic, chỉ giữ lại pattern/cấu trúc/token.


