Skip to content

Ả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Ở đâuViệ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ảngapps/web/src/site/illustrations/registry.jsonNguồ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.tsxApp.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 build của web chạy apps/web/scripts/illustrations.mjs trước vite build, ghi public/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. --add chỉ 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òng hero.
  • 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 ​

bash
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:

ẢnhTrướcNay
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 KBsinh 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 JSXIllustration 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ẽ taydò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ộng site (learn) và file_path (URL file tĩnh, hoặc inline:<file>#<khoá> cho cảnh render trong React). id luôn bắt đầu bằng learn-- để không đụng khoá chính của dòng www trong D1. Seed riêng scripts/seed-illustrations-learn.sql chỉ xoá và ghi dòng site = '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.json là 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à gender trê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).
bash
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"