---
url: https://docs.nemo12.com/product/marlins-ia/art-and-home.md
description: >-
  Marlins: ảnh khoá học sinh bằng thuật toán, màu từ sân IELTS, album ảnh, bìa
  sách chung hệ vẽ, chỉ tiếng Việt, key concept, thanh menu.
---

# Marlins IA · Ảnh khoá học, bìa sách, trang chủ và thanh menu

Một phần của [Marlins IA](./index.md). ảnh khoá học sinh bằng thuật toán, màu từ sân IELTS, album ảnh, bìa sách chung hệ vẽ, chỉ tiếng Việt, key concept, thanh menu.

## Ảnh khoá học sinh bằng thuật toán (SRC-1171)

Chỉ đạo chủ dự án 01.10.2026: mọi khoá trên marlins cần **ảnh thumbnail** trên thẻ và **ảnh hero**
trên trang chi tiết, ảnh **sinh bằng thuật toán, dạng SVG**.

Áp cho cả hai loại khoá đang có trên cổng: 15 khoá của bố mẹ (`/parent-courses`) và các lớp có
lịch của con (`/courses`). Mã ở `apps/marlins/src/CourseArt.tsx`.

**Hạt giống là định danh của khoá**, không phải `Math.random`: `code` với khoá bố mẹ, `id` với lớp
của con, băm FNV-1a rồi bơm vào mulberry32. Ảnh nhảy mỗi lần tải lại trang thì nó thôi làm được
việc nhận diện, và ảnh trên thẻ sẽ khác ảnh trên trang chi tiết của cùng một khoá.

**Màu CÓ NGHĨA, chỉ hoạ tiết mới ngẫu nhiên.** Khoá bố mẹ lấy màu theo NHÓM (5 nhóm của Parent
Learning System), lớp của con lấy theo MÔN. Nhờ vậy 15 thẻ cạnh nhau đọc ra 5 cụm, và màu nói thêm
một điều thật thay vì chỉ trang trí. Khoá chưa khớp nhóm hay môn nào vẫn rơi vào một bảng màu dự
phòng ổn định: một thẻ mất ảnh giữa những thẻ có ảnh trông như lỗi tải, không như một lựa chọn.

**Chữ trắng trên hero là một ràng buộc đo được, không phải một cảm giác.** Cổng contrast
(AS-09.3.1) đo token nền khai báo trong CSS nên nó KHÔNG nhìn thấy một tấm SVG, đúng loại chỗ đã
lọt lưới ở SRC-672. Vì vậy hero có thứ tự vẽ riêng: phủ tối lên nước TRƯỚC, rồi vẽ hoạ tiết đè lên
với độ mờ bị chặn trên. Điểm ảnh sáng nhất của hero do đó là một con số biết trước, và
`apps/marlins/src/CourseArt.test.ts` tính lại tỉ lệ tương phản của chính con số ấy cho cả 8 bảng màu. Ca tệ nhất
hiện ở 6,5:1, ngưỡng là 4,5:1.

Bản đầu phủ tối LÊN TRÊN hoạ tiết và đó là một lỗi đáng ghi: nét vẽ 0,42 nằm dưới một lớp phủ 0,72
chỉ còn đóng góp 0,12, nên hero ra một tấm xanh phẳng, tốn một tấm ảnh mà không ai nhìn thấy nó.
Hero cũng phải có **chiều cao tối thiểu**: để chiều cao chạy theo độ dài tiêu đề thì khung
1200x360 bị cắt còn một dải mỏng và hoạ tiết biến mất.

**Lớp của con nhận ảnh qua một prop, không phải qua sửa thân panel.** `CoursesPanel` là file
canonical của DS có hai bản sao y hệt ở learn và marlins, nên nó nhận `art` là một HÀM VẼ do app
truyền vào: marlins truyền hàm sinh ảnh, learn không truyền gì và giữ nguyên hình cũ y hệt.

Khi có ảnh thật, `CourseArt` nhận thêm một `imageUrl` và ảnh sinh lùi về làm ảnh dự phòng; không
có dữ liệu nào phải sửa.

## Lấy màu và kích thước từ sân IELTS (SRC-1171)

Chỉ đạo chủ dự án 01.10.2026: *"Màu sắc, kích thước của giao diện, cần lấy toàn bộ từ
learn.nemo12.com/ielts. Cụm 'các con' và 'người giám hộ', cần thu nhỏ lại, cất đi đâu đó ở
right-panel. Khóa học, cần là một section. Trình bày thông tin không cần full-width nhé."*

**Thẻ là MÀU ĐẶC, không còn là kính.** Hai cổng đã dùng chung token từ SRC-808, nên thứ còn làm
marlins đọc ra khác sân IELTS không phải bảng màu mà là CHẤT LIỆU của thẻ. learn đã bỏ kính từ
SRC-814: nền tối là một dải chuyển sắc, nên tấm kính lấy màu từ thứ nằm dưới nó, thẻ đầu trang ra
`#233048` còn thẻ cuối trang ra `#131A26`. Năm thẻ cùng vai trò mà mỗi thẻ một màu, càng cuộn
xuống càng nhạt dần: thứ mắt đọc ra là "trang chưa hoàn thiện" mà không chỉ được tên. Nay
`.theme-marlins.od-root [data-slot="card"]` và `.n12-panel` cùng dùng `--card-deep`, và
`backdrop-filter` bị bỏ vì nó tồn tại chỉ để kính lấy màu nền.

**Hết full-width.** SRC-662 từng cho trang chủ chạy hết chiều ngang; nay 22 khối trong 14 file
dùng `n12-page n12-page-wide` (trần 1216px của DS). Trên màn 27 inch, full-width kéo một dòng chữ
dài gần 2000px: mắt đọc hết dòng rồi phải quét ngược gần cả bề ngang màn hình để tìm dòng sau.
`px-4 sm:px-8` viết tay cũng bỏ theo, vì `n12-page` đã tự lo lề ngang; để cả hai thì lề cộng đôi.

Hai ngoại lệ còn full-width: **phòng sự kiện trực tiếp** (`EventRoom`, `EventLive`). Ở đó thứ
chiếm màn là khung hình chứ không phải chữ, và bó khung hình vào 1216px là bỏ phí đúng thứ người
ta vào đó để xem.

**Thanh trên**: dải vẫn chạy hết chiều ngang, nhưng nội dung xếp vào đúng cột của thân trang. Đây
là luật của sân IELTS (`apps/learn/src/ielts/Chrome.tsx`): lệch lề giữa thanh trên và thân trang
thì logo không thẳng hàng với dòng đầu trang, và mắt đọc ra hai khối rời.

**Gia đình sang phải và thu gọn.** "Các con" và "Bố mẹ & người giám hộ" là thứ để LIẾC, còn cột
chính là thứ để đọc, nên cột đọc đứng trước theo thứ tự đọc tự nhiên và panel phải vẫn dính khi
cuộn. Mỗi con rút còn một dòng tên, một dòng trạng thái cỡ 11px và huy hiệu số việc; viền quanh
từng dòng bỏ đi vì ở chỗ để liếc nó chỉ thêm một đường kẻ chứ không thêm thông tin.

**Khoá học là một SECTION.** Bản cũ bọc ba khoá trong một `Card`, thành thẻ trong thẻ: mắt đọc hai
tầng khung trước khi tới tên khoá, mà tầng ngoài không mang thông tin nào. Nay tiêu đề đứng trần
trên nền trang như các mục ở sân IELTS, và ba khoá là ba thẻ thật có ảnh thumbnail.

## Ảnh Marlins ngoài đời thật (SRC-1226)

Chỉ đạo chủ dự án 04.10.2026: *"Hiển thị các ảnh liên quan tới Marlins lên nhé. Vừa có album nào
đó liên quan tới Marlins mà được đưa lên qua dolphin.nemo12.com rồi."*

Album `marlins` trong kho ảnh chung (13 ảnh buổi offline với phụ huynh ở Hồ Chí Minh, mentor đưa
lên qua dolphin) hiện thành một dải sáu ảnh vuông trên trang chủ cổng phụ huynh, ngay dưới khối
khoá học.

**Vì sao ở trang chủ và vì sao ngay dưới khoá học.** Mọi thứ khác trên trang này là chữ: khoá học,
sách, chỉ số. Một dải ảnh những người đã ngồi cùng nhau nói "đây là cộng đồng người thật" nhanh
hơn bất kỳ câu nào, và đó là thứ duy nhất trên trang không viết ra được. Để tận cuối thì nó nằm
dưới bảy khối và gần như không ai cuộn tới.

**Đọc qua đường SAU ĐĂNG NHẬP, không qua đường công khai.** Album đang ở trạng thái `draft`.
`/v1/public/albums/{slug}` chỉ trả album đã đăng, nên muốn dùng nó thì phải đăng album - mà đăng
là đưa mặt những phụ huynh có thật lên `nemo12.com` web mở, trong khi
[SDD-053](../../architecture/sdd-053-photo-library-placements.md) (03.10.2026) vừa ghi rõ hệ **chưa có
chỗ nào lưu sự đồng ý** của người trong ảnh. Hai việc ấy tách ra: hiện cho chính cộng đồng đã đăng
nhập là một quyết định, đăng ra web mở là một quyết định khác và thuộc về người tổ chức buổi chụp.
Vì vậy có `GET /v1/parent/albums/{slug}` (đòi phiên đăng nhập) và `getMemberAlbum` không lọc
`status='published'`.

Hai cổng của bản công khai giữ nguyên ở đường mới: ảnh `visibility='internal'` không ra ngoài
(SRC-1191), và album `archived` thì không đọc được ở đâu cả. `member-album.test.ts` khoá cả hai,
cộng một ca khẳng định **đường công khai vẫn không thấy album chưa đăng** - nới một đường không
được nới đường kia.

**Không chép ảnh sang đâu.** Marlins đọc thẳng album trong kho ảnh chung, nên sửa chú thích hay
thứ tự ở dolphin là marlins đổi theo, và không có bản thứ hai để lệch nhau.

Ba luật của khối này giống các khối xem trước khác: tối đa một dải chứ không phải cả album; album
rỗng hoặc chưa có ảnh nào thì **không hiện khung trống**; lỗi mạng thì im lặng, vì thiếu một dải
ảnh không được làm hỏng trang chủ.

## Bìa khoá học và bìa sách: một hệ vẽ chung với www và learn (SRC-1235)

Chỉ đạo chủ dự án 05.10.2026: *"Các cover của các khóa học cần đa dạng và cực kỳ chi tiết vào. Đều
cần dùng thuật toán để sinh ra SVG, cần lưu hết cả prompt lẫn các meta data để sinh ra course cover
vào database."* Cùng ngày: bìa sách phải chi tiết *"giống như books mà hiển thị ở
www.nemo12.com/ielts"*, *"hoặc đồng nhất 2 loại book vào thành 1 loại là tốt nhất"*.

**Không dựng hệ thứ hai.** Main đã có đúng thứ được yêu cầu: hệ ảnh minh hoạ SRC-1201
(`@nemo12/illustrations`, bảng D1 `illustrations`), learn đã dùng ở SRC-1203. Mỗi bìa khoá học nay
là MỘT CẢNH: nhân vật mang cảm xúc qua bốn kênh (mắt, lông mày, miệng, dấu cạnh đầu) cộng tư thế
tay, nền nhiều lớp có gradient và texture, đồ vật gắn với chủ đề khoá. 19 dòng spec (15 khoá bố mẹ,
4 lớp của con) ở `apps/marlins/src/illustrations/registry.json`, mỗi dòng có prompt tiếng Anh viết
riêng cho khoá đó cùng scene, nhân vật + cảm xúc, đồ vật, bảng màu, seed, phiên bản bộ vẽ. Bản sao
D1 là `scripts/seed-illustrations-marlins.sql` (site `marlins`), nạp qua workflow `seed-data`.

**Đa dạng là một bất biến có test**: 15 khoá bố mẹ là 15 cảnh khác nhau, 19 bìa là 19 hạt giống khác
nhau. Bìa cũ khác nhau đúng ở một đường sóng.

**Bẫy đã gặp: spec khai hai người, ảnh vẽ một.** Năm cảnh của bộ vẽ (`desk`, `focus`, `growth`,
`exam`, `reading`) chỉ vẽ đúng MỘT nhân vật, nên bốn khoá đầu tiên ra ảnh chỉ có bố trong khi prompt
lưu trong D1 tả "bố và con gái" - tức là cơ sở dữ liệu tả một tấm ảnh không tồn tại. Ba khoá đổi
sang cảnh hai người; *How Children Actually Learn* giữ cảnh `focus` một người và prompt viết lại cho
khớp, vì khoá ấy nói về MÔI TRƯỜNG bố mẹ dựng, và đứa trẻ một mình trong môi trường ấy đúng là
thông điệp. Test chặn cảnh một người khai hai người.

**Hero không còn chữ đè lên ảnh.** Bìa cũ tối và thưa nên phủ thêm lớp tối là đọc được chữ trắng;
bìa mới là một cảnh sáng nhiều chi tiết, phủ tối lên nó là tắt đúng phần chi tiết vừa được yêu cầu.
Ảnh ở trên (cắt dải ~3,5:1), chữ ở dưới.

**Lớp mới của con** nạp từ D1, nên lớp mở sau ngày hôm nay chưa có dòng trong registry. Nó lùi về
ảnh sinh tại chỗ (`CourseArt.tsx`) thay vì thành một thẻ trống.

**Bìa sách: đồng nhất với sách www.** Sách Marlins nay vẽ bằng đúng bộ vẽ của www
(`@nemo12/books/draw`): nền chuyển màu có hoa văn và hoa giấy, một hình chính CÓ NGHĨA với quyển
sách, tấm nhãn ghi bộ, số quyển, tên sách. Hình chính, bảng màu và câu nói nghĩa của từng quyển ở
`apps/marlins/src/ebookCovers.ts`; không hai quyển nào chung một hình chính. `package.json` của
`@nemo12/books` mở thêm lối vào `./draw` để marlins chỉ kéo bộ vẽ, không kéo khoảng 600 KB nội dung
sách www.

**Sửa luôn một lỗi của bộ vẽ chung.** Nó ngắt tên 11 ký tự một dòng rồi cắt cứng ở ba dòng: tên dài
MẤT CHỮ một cách im lặng, và ba dòng cỡ lớn rơi ra ngoài mép bìa. Hai bìa www đã hỏng như vậy trên
production mà chưa ai thấy (*Paragraph by Paragraph*, *Holding Ideas Together*: dòng thứ ba ở y = 422
trên bìa cao 400). Nay bìa nào bố cục cũ đã vừa thì giữ nguyên từng byte (39/41 bìa www), chỉ bìa tràn
mới thu cỡ chữ. Test kiểm mọi tên của cả hai thư viện hiện đủ chữ và nằm gọn trong bìa.

## Chỉ còn tiếng Việt (SRC-1235)

Chỉ đạo chủ dự án 05.10.2026: *"Bỏ cái Switch chọn ngôn ngữ ở góc trên phải trên mọi trang. Mặc định
coi như lúc nào cũng chọn tiếng Việt."* Công tắc gỡ khỏi ba chỗ (thanh trên, trang bài học, trang báo
cáo). `useLang` vẫn còn nhưng luôn trả tiếng Việt, và BỎ QUA lựa chọn cũ trong máy người dùng: một
phụ huynh từng chọn EN mà vẫn được đọc lại lựa chọn ấy sẽ kẹt ở tiếng Anh mà không còn nút nào để
đổi lại.

## Trang chủ: ảnh to hơn, sách đứng (SRC-1235)

Dải ảnh Marlins ngoài đời thật thành 2 hàng x 3 ảnh, mỗi ảnh to gấp đôi, đủ để thấy mặt người. Khối
Thư viện Marlins thành 3 quyển đứng với bìa dọc thay cho ba dòng chữ.

## Key concept đầu chương, Big Idea, nghiên cứu liên quan (SRC-1236)

Chỉ đạo chủ dự án 05.10.2026: mỗi chương có 3-5 key concept tiếng Anh kèm giải thích tiếng Việt,
liệt kê ở đầu chương; mỗi chương có Big Idea (rà, thiếu thì bổ sung, có rồi thì giữ); mỗi quyển có
3-5 nguồn nghiên cứu liên quan.

**Rà soát 100 chương trước khi viết gì.** Big Idea: có đủ ở 100/100 chương, giữ nguyên. Key concept:
cũng ĐÃ CÓ ở 100/100 chương nhưng nằm rải trong từng section, không có danh sách đầu chương. Số
concept riêng biệt mỗi chương: 3 ở 61 chương, 4 ở 24, 5 ở 14, và đúng một chương có 7.

**Danh sách đầu chương dựng từ chính thân chương** (`ebookChapters/chapterConcepts.ts`), không soạn
bộ thứ hai: hai bộ concept cho cùng một chương là hai thứ để lệch nhau. Chương có 7
(*The Self-Driven Child* chương 1) có hai mục thực ra là BÀI TẬP chứ không phải khái niệm (*The
weekly decision map*, *The silence test*): chúng vẫn ở nguyên trong section như công cụ, chỉ không
đứng trong danh sách. Chương ấy còn đúng 5, không sửa chữ nào của thân chương.

**Một khái niệm, một tên.** Tên concept hiện bằng tiếng Anh ở CẢ danh sách đầu chương lẫn trong thân
chương; trước đây thân chương hiện tên tiếng Việt, nên cùng một khái niệm mang hai tên
("The permission tax" và "Thuế xin phép") và người đọc không biết đó là một thứ.

**Nghiên cứu liên quan: không dẫn thứ chưa đối chiếu được.** 61 dẫn nguồn, 41 nghiên cứu khác nhau,
mỗi quyển 3-4 nguồn (`ebookReferences.ts`). Mọi mục đã so với Crossref: tên bài khớp từ 0,85, năm
lệch tối đa một năm, tên tạp chí khớp; DOI là DOI Crossref trả về, không gõ tay. Một mục bị loại vì
không qua được bước ấy (Winnicott 1953 về "good enough mother": Crossref chỉ có bản in lại 2016).
Trên trang giới thiệu từng quyển, câu tiếng Việt nói nghiên cứu ấy liên quan gì tới quyển sách đứng
TRƯỚC tên bài tiếng Anh, vì đó là thứ bố mẹ đọc; tên bài là thứ để tra.

## Thanh trên có menu, trang chủ gọn lại (SRC-1243)

Chỉ đạo chủ dự án 05.10.2026, sáu việc:

1. **Menu chính** trên thanh trên: Khoá học, Thư viện, Sự kiện, Lớp của con, Lịch. Mục nào cũng trỏ
   vào một trang đang chạy (SRC-656). "Lịch" lên thanh trên vì khối "Lịch tuần này" vừa rời trang
   chủ: bỏ khối mà không còn đường tới trang lịch là lấy mất một việc của bố mẹ.
2. **Logo**: cá và chữ Marlins ở dòng trên, câu định danh ở dòng dưới bắt đầu thẳng mép với con cá.
   Bản trước đặt cá bên trái một khối hai dòng, nên dòng dưới thụt vào theo chữ "Marlins".
3. **Ảnh Marlins ngoài đời thật 16:9**: ảnh chụp buổi offline là ảnh ngang, cắt vuông là cắt mất
   người ngồi hai đầu bàn.
4. **Thumbnail khoá học bằng nhau.** Đo trong trình duyệt: ba ảnh vốn CÙNG kích thước (299x150),
   nhưng ảnh của thẻ giữa bị đẩy xuống 11px. Nguyên nhân: `<button>` mặc định căn giữa nội dung theo
   chiều dọc, nên trong một lưới thẻ cao bằng nhau, thẻ có tên khoá ngắn hơn bị đẩy cả ảnh xuống.
   Nút nay là cột flex dồn nội dung lên đỉnh; đo lại 15 thẻ ở trang danh sách, lệch 0px.
5. Bỏ khối **"Lịch tuần này"** khỏi trang chủ.
6. Bỏ khối **"Các school"** khỏi trang chủ (trang các school vẫn ở `/explore`).
