Cinematic portfolio
Trang portfolio một trang, tông tối, lấy cảm hứng từ các trang portfolio của editor và VFX artist: một chữ khổng lồ chìm sau ảnh người, tên đứng trước, tiêu đề hai màu (trắng và một màu nhấn). Khi vào trang có hiệu ứng 30 agent dựng từng khối (skill agent-build-effect, đã kèm sẵn trong template/vendor/).
template/
index.html khung trang, không cần sửa
data.js TOÀN BỘ nội dung, chỉ sửa file này
styles.css giao diện; màu đổi qua biến hoặc `accent` trong data.js
portfolio.js dựng trang từ data.js, rồi khởi động hiệu ứng agent
vendor/ agent-build.js + .css
assets/ ảnh người tách nền + ảnh thẻ năng lực (mẫu: 6 ảnh tối/đỏ)
scripts/cutout.py tách nền ảnh người (rembg)
references/image-prompts.md prompt ảnh thẻ, cùng một phong cách
Quy trình
1. Hỏi đủ thông tin trước khi làm
Hỏi gọn trong một lượt, những gì người dùng chưa đưa:
- Tên gọi ngắn để in to (một từ là đẹp nhất), họ tên đầy đủ, chức danh, một câu giới thiệu.
- Ảnh người: ảnh từ đầu gối trở lên hoặc toàn thân, nền không quá rối, đứng hơi nghiêng. Ảnh thật hay ảnh 3D đều được.
- 3 đến 6 năng lực hoặc dự án muốn khoe (tên, một câu mô tả, công nghệ). Có dự án thật kèm link thì đặt
hrefcho thẻ. - Hành trình (công việc, học vấn), kỹ năng, quy trình làm việc, câu trích dẫn.
- Ghi nhận hoặc báo chí (không có thì bỏ cả phần).
- Liên hệ: email, khu vực, nút kêu gọi.
- Ngôn ngữ trang, màu nhấn (mặc định đỏ
#ff3b30), chữ chìm (mặc địnhPORTFOLIO).
Không bịa số liệu, giải thưởng hay báo chí. Mục nào người dùng không có thì xoá khỏi data.js, trang sẽ tự bỏ phần đó.
2. Chép mẫu
Chép cả thư mục template/ sang chỗ người dùng muốn (ví dụ ./my-portfolio/). Không sửa mẫu gốc trong skill.
3. Tách nền ảnh người
pip install rembg pillow
python -I <skill>/scripts/cutout.py anh-goc.jpg my-portfolio/assets/photo.webp
Model mặc định isnet-general-use nhẹ (~180 MB, tải một lần). Chỉ thử birefnet-portrait khi máy nhiều RAM: model này nặng ~1 GB và từng hết bộ nhớ với ảnh 1440px. Xem lại một lần trên nền xám (ghép nền xám bằng PIL rồi Read ảnh). Phải giữ được tóc, kính và đồ cầm tay. Đặt hero.photo thành assets/photo.webp.
4. Ảnh cho thẻ năng lực
Mẫu có sẵn 6 ảnh tối/đỏ (agent, tự động hoá, web, chatbot, bảng tính, video). Dùng lại được nếu khớp nội dung thẻ. Muốn ảnh riêng thì làm theo references/image-prompts.md: giữ nguyên đuôi phong cách, chỉ đổi chủ thể. Đổi màu nhấn thì đổi cả mã màu trong prompt. Hỏi người dùng trước khi gọi tạo ảnh hàng loạt (tốn hạn mức tài khoản của họ).
Không có ảnh khớp thì bỏ image của thẻ đó, thẻ vẫn hiển thị đẹp mà không có ảnh. Không dùng một ảnh cho hai thẻ khác nội dung.
5. Điền data.js
hero.name: một từ, in hoa tự động. Tên dài quá 7 ký tự thì giảm cỡ trong.pf-name.hero.stats: chỉ ghi số thật (số năng lực, số năm, số công nghệ...).- Tiêu đề section gồm
title(trắng) vàaccent(màu nhấn). Hai vế ngắn đọc mạnh nhất: "Not just code." / "Solutions that run." agents.labels: dịch theo ngôn ngữ trang. Ví dụ tiếng Việt:{ status: "{agents} agent · {edits} chỉnh sửa", building: "Đang dựng trang", done: "Đã dựng xong", skip: "Bỏ qua" }.- Văn bản được đưa vào bằng
textContent, nên không chèn được HTML (đây là chủ ý, an toàn).
6. Kiểm tra (bằng số trước, ảnh sau)
Mở index.html trực tiếp bằng trình duyệt (file:// chạy được) hoặc chạy một server tĩnh bất kỳ. Dùng Playwright ở 1440×900 và 390×844 với ?agents:
({
sections: document.querySelectorAll(".pf-section").length,
overflowX: document.documentElement.scrollWidth > innerWidth, // phải false
photo: document.querySelector(".pf-photo img")?.naturalWidth, // > 0
waiting: document.querySelectorAll('[data-ab="wait"]').length, // về 0 sau khi cuộn hết
})
Cuộn bằng window.scrollTo theo từng bước 600px, mỗi bước chờ khoảng 1 giây, rồi kiểm tra waiting đã về 0 và không có lỗi console. Chụp một ảnh hero ở mỗi kích thước để đánh giá phần nhìn. Chú ý: đoạn giới thiệu không được đè lên người, và trên điện thoại mặt không được bị chữ che.
7. Đưa lên mạng
Thư mục là web tĩnh: kéo thả vào Netlify Drop, vercel deploy, GitHub Pages hoặc Cloudflare Pages. Không cần build.
Đưa vào dự án Next.js / React có sẵn
Dùng lại styles.css, đổi :root thành .pf. Viết lại phần render thành component server, giữ nguyên tên class. Gắn hiệu ứng bằng AgentBuild.tsx của skill agent-build-effect, với cùng danh sách targets như trong portfolio.js. Những điểm đã gặp khi làm bản Next:
- Header nổi dạng sticky: cho trang
margin-topâm bằng chiều cao header để hero luồn dưới header. - Ảnh
next/imagedùngfillcần khung cha cóposition: relative, nếu không ảnh phủ kín cả trang. - Font Anton có bộ ký tự tiếng Việt. Khi tự host thì tải đủ 3 subset latin, latin-ext, vietnamese.
- Dev server Turbopack đôi khi bỏ lỡ thay đổi CSS sửa bằng
sed. Sửa bằng công cụ Edit hoặc ghi lại file thì nó nhận lại.