Ảnh minh họa trang
SRC-1201 (chủ dự án, 03.10.2026): mọi trang có ảnh minh họa chi tiết, giàu cảm xúc, dạng SVG sinh bằng thuật toán; mỗi ảnh là một dòng trong một bảng, dòng ấy giữ cả prompt sinh ảnh và đủ thông số để nâng cấp về sau. Cùng ngày chủ dự án thêm: tạo lại toàn bộ ảnh minh họa theo một tiêu chuẩn mới, dùng skill mới. Skill: .claude/skills/page-illustration/SKILL.md.
Ba phần
| Phần | Ở đâu | Việc |
|---|---|---|
| Bộ vẽ | packages/illustrations (@nemo12/illustrations) | renderIllustration(spec) trả về một chuỗi SVG; cùng spec ra cùng từng byte. Dùng chung cho web và learn. |
| Bảng | apps/web/src/site/illustrations/registry.json | Nguồn chuẩn, một dòng một ảnh. Bản sao trong D1: bảng illustrations (migration 0326), nạp bằng scripts/seed-illustrations.sql. |
| Khe hiển thị | apps/web/src/site/illustrations/PageIllustration.tsx | App.tsx gọi PageIllustration ngay dưới phần đầu trang cho MỌI trang; ContentPage gọi nó cho trang nội dung; ProgramTabPage gọi SectionIllustration cho từng thẻ ở tab Kết quả. |
Cột của bảng
id, pages (các đường dẫn), placement (hero hoặc section:<key>), title, alt_vi, prompt (câu mô tả đủ để vẽ lại hay nâng cấp ảnh, bằng thuật toán này hoặc bằng một model sinh ảnh), scene, characters (vai + cảm xúc), props, palette, seed, label, generator_version, width, height, created_at, updated_at, status (auto = phác từ metadata trang, tuned = chỉnh tay, draft), notes. D1 thêm site và file_path.
Quyết định
- SVG sinh lúc build, không commit.
npm run buildcủa web chạyapps/web/scripts/illustrations.mjstrướcvite build, ghipublic/art/pages/*.svg(đã gitignore). Cái được commit là BẢNG, vì bảng mới là thứ người ta sửa; 729 file SVG khoảng 10 MB trong git chỉ là bản sao của bảng. - Dòng đã có thì không phác lại.
--addchỉ thêm dòng cho trang chưa có. Đổi tiêu đề trang không làm đỏ cổng; nâng cấp một ảnh là sửa dòng của nó rồi chạy--sync. - Một khe ở tầng route thay vì gắn tay từng trang, nên trang mới không thể thiếu ảnh; cổng
illustrations.test.tsđỏ nếu một trang prerender chưa có dònghero. - Trang động (
/mentors/{slug}...) không có dòng riêng thì dùng ảnh họfamily-<đoạn đầu>. - Alt tiếng Việt nằm ở chunk lười
alts.jsonđể bundle chính không chở 700 câu; trong lúc chờ, ảnh dùng câu hỏi của trang làm alt tạm. - Kích thước: hero 960x400 (trên điện thoại cắt giữa về 16:9), thẻ 480x300. Trung bình 12 KB, trần 25 KB mỗi file do cổng giữ.
Lệnh
cd apps/web
npm run illustrations:add # thêm dòng cho trang mới, ghi lại alts.json + seed
npm run illustrations:sync # sau khi sửa tay một dòng
npm run illustrations # vẽ ra public/art/pages (build tự chạy)
gh workflow run seed-data.yml -f file=scripts/seed-illustrations.sql \
-f verify="SELECT status, COUNT(*) FROM illustrations GROUP BY status"Learn (SRC-1203)
SRC-1203 (chủ dự án, 03.10.2026): "tạo lại toàn bộ các ảnh minh họa, theo một tiêu chuẩn mới, dùng skill mới tạo". Mọi ảnh minh họa vẽ tay của learn đã chuyển sang bộ vẽ chung, giữ nguyên tên file và URL nên không chỗ nào gãy:
| Ảnh | Trước | Nay |
|---|---|---|
8 ảnh NEMO WALK /art/walk/*.svg (hero, phone-away, after, cathedral, ngoc-son, turtle-tower, ly-thai-to, dinh-le) | SVG vẽ tay 1 tới 7 KB | sinh từ dòng learn--walk-*, ghi ra CẢ apps/learn/public và apps/web/public (commit, vì là file tĩnh hai app cùng phục vụ) |
Ảnh 22 bài Speak together + thẻ NEMO WALK + bài dự phòng (PairScene) | 25 cảnh vẽ tay trong JSX | Illustration render inline dòng learn--speak-<topic>, bản thẻ 2:1 và bản banner |
Ảnh trang "How a session works" (SessionScene) | laptop vẽ tay | dòng learn--speak-session |
- Bảng riêng của learn ở
apps/learn/src/illustrations/registry.json, cùng cột với bảng www cộngsite(learn) vàfile_path(URL file tĩnh, hoặcinline:<file>#<khoá>cho cảnh render trong React). id luôn bắt đầu bằnglearn--để không đụng khoá chính của dòng www trong D1. Seed riêngscripts/seed-illustrations-learn.sqlchỉ xoá và ghi dòngsite = 'learn'. - Inline thay vì file cho cảnh Speak together, vì e2e và bố cục đang dựa vào chính phần tử
<svg>(data-variant=banner, tỉ lệ 4:1).src/illustrations/specs.jsonlà bản rút gọn (không prompt) mà bundle chở; id gradient trong SVG có tiền tố theo từng instance nên nhiều cảnh trên một trang không dùng chung id. - Bộ vẽ 1.1.0 thêm 13 bối cảnh hội thoại (
classroom,living-room,cafe,park,city-street,shop,rainy-day,beach,school-gate,library,tech-room,city-country,video-call), 8 cảnh Hồ Gươm (lake-tour,cathedral,ngoc-son,turtle-tower,ly-thai-to,book-street,street-food,phone-away), 16 đồ vật mới (điện thoại, ô, vali, máy ảnh, biển chỉ đường, bát phở, bánh rán, trà chanh, đàn ghi ta, bóng, thùng tái chế, táo, ảnh gia đình, túi mua sắm, diều, tạ), bóng thoại co giãn theo nhãn, vàgendertrên nhân vật: bạn nam luôn áo xanh tóc ngắn, bạn nữ luôn áo cam đỏ tóc dài, khớp hai icon đọc to. Mọi cảnh 1.0.0 vẫn ra đúng từng byte (đã so 730 file www), nên dòng www giữ1.0.0. - Ngoài phạm vi: mascot và icon của
N12Art.tsx(ngôn ngữ icon DS-001, cỡ 40px, không phải cảnh), hình toán học (figures/,explore/), biểu đồ, bìa sách (packages/books).
cd apps/learn
npm run illustrations # vẽ /art/walk cho learn + www, ghi specs.json + seed learn
npx vitest run src/illustrations
gh workflow run seed-data.yml -f file=scripts/seed-illustrations-learn.sql \
-f verify="SELECT site, COUNT(*) FROM illustrations GROUP BY site"