Dựng video ra mắt nền tảng bằng Claude Code, Google Flow và VieNeu-TTS

Trong bài này
Sáng 10/10/2026, nền tảng Hòa Vang Connect (xã Hòa Vang, Đà Nẵng) ra mắt. Chúng tôi cần một video giới thiệu, và thời gian từ lúc chốt ý tưởng đến lúc lên sân khấu chỉ khoảng vài ngày. Tôi chọn một hướng khác: để Claude Code viết code dựng video, kết hợp Google Flow (Veo) cho clip minh họa và VieNeu-TTS cho giọng đọc. Bài này kể lại cách làm và những chỗ tôi vấp.
Vì sao dựng video bằng code
Video giới thiệu phần mềm phần lớn là màn hình ứng dụng kèm chữ và số liệu, nên hợp với code (HTML/CSS) hơn là kéo thả timeline. Lợi ích lớn nhất là sửa rất nhanh: lãnh đạo góp ý “đổi số này”, “đưa phần quản trị lên trước”, tôi nói với Claude Code, sửa vài dòng rồi render lại đúng đoạn bị ảnh hưởng. Video chính đã qua gần chục phiên bản (v1.0 đến v1.8, chưa kể hai video tình huống riêng), và tôi dám sửa liên tục vì mỗi lần sửa không phải dựng lại từ đầu.
Tôi đặt một file CLAUDE.md ở thư mục dự án ghi rõ: bối cảnh, cách xưng hô, các quy tắc cứng. Mỗi lần mở phiên mới, Claude Code đọc lại và không “quên luật”. Vài quy tắc trong đó tôi thấy đáng viết ra ngay từ đầu:
- Hình ảnh chỉ có một nguồn duy nhất (một file HTML).
- Không đưa thông tin cá nhân lên hình, ảnh chụp mới phải qua script xử lý.
- Số liệu nào cũng phải được tôi xác nhận, không tự đọc từ ảnh chụp.
- Dời một cảnh thì phải dời hiệu ứng âm thanh tương ứng.
Render xác định: mọi khung hình là một hàm của thời gian
Ý tưởng cốt lõi, và cũng là thứ cứu tôi nhiều nhất: toàn bộ hình ảnh là một hàm thuần renderFrame(t). Cho vào thời điểm t giây, hàm vẽ ra đúng khung hình tại đó. Không dùng CSS animation hay transition (vì chúng chạy theo đồng hồ thật), không Date.now(), không Math.random() (thay bằng hàm ngẫu nhiên có seed cố định cho các hạt sao nền).
Nhờ vậy, render lần nào cũng ra kết quả giống hệt nhau, và có thể:
- Xem trước một khung bất kỳ: gọi
renderFrame(58)là thấy giây thứ 58. - Render song song: tám tiến trình Playwright (Chromium headless) mỗi cái chụp một đoạn thời gian. 148 giây ở 60 fps là 8.880 ảnh.
- Render lại đúng đoạn sửa: tên file đánh số theo thời gian tuyệt đối, sửa đoạn nào thì chỉ render và ghi đè đoạn đó.
Cuối cùng ffmpeg ghép chuỗi ảnh với âm thanh thành MP4.
Quy trình kiểm tra: contact sheet trước, render đầy đủ sau
Render cả video tốn nhiều thời gian, nên tôi không để Claude Code render rồi mới xem. Quy trình cố định là: render ảnh tĩnh ở các mốc thời gian quan trọng, ghép thành một contact sheet (một ảnh lớn chứa nhiều khung nhỏ), xem kỹ chữ, bố cục, số liệu rồi mới cho render đầy đủ. Lỗi chính tả, chữ tràn khung, số sai thường bị bắt ở bước này, rẻ hơn rất nhiều so với phát hiện sau khi xuất file.
Claude Code hay báo “đã sửa xong” khi code đã đổi, còn hình có đúng hay không thì chỉ ảnh tĩnh mới trả lời được. Tôi coi ảnh tĩnh là bằng chứng, lời AI thì chưa.
Nhạc và hiệu ứng: tự tổng hợp bằng numpy
Video công bố trước lãnh đạo và có thể phát lại ở nhiều nơi, nên tôi không muốn rủi ro bản quyền nhạc. Giải pháp: tự sinh toàn bộ nhạc nền và hiệu ứng âm thanh bằng Python (numpy, scipy). Chưa đến 170 dòng Python, Claude Code viết được:
- Nhạc nền nhịp 120 BPM, dày dần ở đoạn giữa, dâng lên rồi dịu xuống ở cuối.
- Tiếng whoosh chuyển cảnh (nhiễu lọc băng thông), riser, tiếng chạm cho thao tác giả lập trên điện thoại, tiếng ding khi hiện số liệu.
Chất lượng không bằng nhạc sĩ, nhưng đủ sạch và khớp từng nhịp với hình, vì chính code quyết định mốc thời gian của cả hai. Nhược điểm: dời một cảnh thì mốc âm thanh phải dời theo (tôi viết hàm remap() cho việc này), nếu không tiếng “pop” sẽ lệch khỏi thao tác trên màn hình. Tôi cũng xuất riêng bản “không lời” và “không nhạc” để đơn vị khác dùng lại.
VieNeu-TTS: giọng đọc tiếng Việt chạy local
Cho lời bình, tôi dùng VieNeu-TTS, mô hình TTS tiếng Việt mã nguồn mở, chạy trên GPU của máy cá nhân, giọng “Hải Đăng”. Vì sao không dùng dịch vụ đám mây:
- Không giới hạn số lần thử: kịch bản đổi liên tục, mỗi phiên bản lại phải thu lại vài câu.
- Dữ liệu kịch bản không rời khỏi máy.
- Điều khiển được từng câu: tôi khai báo danh sách
(giây bắt đầu, phải xong trước giây, lời), script thu từng câu, đặt đúng mốc cảnh và in bảng kiểm tra câu nào dài hơn khoảng cho phép.
Hai mẹo nhỏ. Cache theo nội dung câu: câu không đổi thì không thu lại, sửa một câu chỉ mất vài giây. Và viết số thành chữ trong lời bình (“bốn trăm năm mươi tám tài khoản”). Câu quá dài thì rút gọn lời chứ đừng ép đọc nhanh, vì giọng bị ép nghe rất lộ.
Google Flow (Veo): clip minh họa, nhưng phải nói rõ là minh họa
Phần “tình huống đời thường” (một đôi vợ chồng đăng ký khai sinh cho con ngay tại nhà trên điện thoại) tôi không có phim quay thật, nên dùng Google Flow với model Veo để sinh các clip ngắn. Vài kinh nghiệm:
- Chia thành nhiều clip ngắn, mỗi clip một hành động. Có thể dùng khung cuối clip trước làm khung đầu clip sau để giữ nhân vật, nhưng Veo vẫn “vẽ lại” nên tư thế luôn lệch một chút.
- Gắn nhãn “Hình ảnh minh họa” trên mọi clip AI. Đây là video của cơ quan nhà nước, không được để người xem tưởng là người thật việc thật.
- Màn hình điện thoại do AI sinh ra chỉ là chữ vô nghĩa, tôi cần app thật hiện trên đó.

Ghép màn hình app vào clip AI bằng OpenCV
Cách làm: dò vùng màn hình sáng trong từng khung, lấy hình chữ nhật xoay nhỏ nhất bao quanh, ép về tỉ lệ cao/rộng cố định (điện thoại là vật cứng), làm mượt góc, kích thước, tâm theo thời gian bằng bộ lọc trung vị và Savitzky-Golay, rồi dán ảnh app vào bằng phép biến đổi phối cảnh. Phần da tay che trước màn hình được loại khỏi mặt nạ.
Bản đầu tôi dò từng khung riêng lẻ nên màn hình app rung rất khó chịu. Làm mượt theo thời gian mới là chỗ quyết định, không phải thuật toán dò.
![]()
Đo thay vì đoán
Video tình huống 2 có một đoạn giật cục quanh phút 1:20. Tôi và Claude Code đoán đủ thứ (hiệu ứng chuyển, tốc độ phát) mà đều sai. Cuối cùng tôi bảo Claude đo từng khung hình của file đã xuất: khung nào trùng khung trước, khung nào đột biến. Kết quả: 46 khung bị lặp, cứ khoảng 0,25 giây một lần.
Nguyên nhân: tôi làm chậm clip bằng -r 24 của ffmpeg, và nó chèn khung lặp để đạt tốc độ. Sửa lại (giữ nguyên số khung, đặt -r bằng 24 nhân tốc độ) cùng vài chỉnh sửa khác (tư thế khung đầu clip, mức phóng hai clip không khớp), đo lại: khung trùng từ 46 về 0, độ đột biến giảm từ 4,57 còn 1,84.
Khi lỗi là thứ mắt thấy mà không gọi được tên, hãy đo. AI và con người đều rất giỏi bịa lý do nghe hợp lý.
Đối chiếu khi nhờ AI review
Tôi nhờ Gemini xem video và nhận xét. Review hữu ích: nó gợi ý đưa số liệu ra sau phần quản trị, ghi rõ “giai đoạn thử nghiệm”. Nhưng nó cũng khẳng định danh sách đối tác tiện ích trên màn hình có Gojek. Tôi chạy OCR đúng khung đó: không có. Với AI review, tôi giữ nguyên tắc: gợi ý thì cân nhắc, khẳng định về sự kiện thì kiểm tra bằng công cụ độc lập trước khi sửa.
Dữ liệu mẫu hư cấu thay vì làm mờ
Ảnh chụp hệ thống thật có tên, số định danh của người dân. Làm mờ thì xấu và gợi tò mò, nên tôi đổi sang tên mẫu hư cấu và số che theo kiểu hệ thống: một script vẽ lại chữ lên đúng vùng đó, góc màn hình ghi “Dữ liệu minh họa”. Quy tắc nằm trong CLAUDE.md nên Claude Code không quên đưa ảnh mới qua script.
Bản 2K và chuyện vệt màu nền tối
Video chiếu màn lớn ở hội trường nên tôi xuất thêm bản 2K (2560×1440), render với mật độ điểm ảnh gấp 4/3 trên cùng trang 1920×1080. Nền gradient xanh đậm khi nén bị banding: các vệt màu bậc thang lộ rõ trên màn lớn. Cách chữa là thêm nhiễu hạt rất nhẹ (noise=alls=1.5), -tune grain và bitrate khoảng 30 Mbps. Hạt nhiễu phá các bậc màu, mắt hầu như không nhận ra có nhiễu.

Bài học tôi giữ lại
- Cho AI một quy trình, không chỉ một yêu cầu:
CLAUDE.md, contact sheet trước render, số liệu phải qua tôi. - Hình là hàm của thời gian thì sửa và render lại rất rẻ. Đây là điều tôi muốn áp dụng cho mọi video tiếp theo.
- Cái gì đo được thì đo, đừng đoán và đừng tin lời AI nói về lỗi.
- Cảnh AI sinh phải gắn nhãn, và dữ liệu cá nhân phải thay bằng dữ liệu hư cấu ngay từ đầu.
- Phần tốn thời gian nhất là vòng góp ý, không phải code. Hạ tầng sửa nhanh giúp tôi theo kịp.
Kết
Một người, vài ngày, và video 2,5 phút phát được trên sân khấu: không phải nhờ AI “làm hết”, mà nhờ AI làm nhanh những việc lặp lại trong khi tôi giữ quyền quyết định và kiểm tra. Nếu cần dựng video giới thiệu sản phẩm phần mềm, tôi khuyên thử cách này: kịch bản chắc chắn sẽ đổi liên tục, và lúc đó một dự án code dễ sửa hơn nhiều so với một file timeline.