Bỏ qua, tới nội dung chính
LiveBridgeLiveBridge

Bắt đầu nhanh

Đây là đúng tài liệu mà bộ khởi đầu gửi cho trợ lý AI (AGENTS.md). Đưa nó cho Claude, Cursor hay Copilot và nhờ làm game.

Quy trình làm việc

  1. npx @livebridge/dev init ten-game tạo thư mục từ game mẫu (id: 3-40 ký tự a-z, 0-9, dấu -, không đổi được sau này).
  2. Sửa game.js, index.html, style.css, manifest.json.
  3. npx @livebridge/dev serve chạy thử ở http://localhost:5173/index.html?t=lbg_dev. Mở thêm http://localhost:5173/__panel: panel giả lập bấm quà, chat, like, follow, share, người vào phòng, đổi tên và avatar người xem, bật/tắt gửi tên và avatar.
  4. npx @livebridge/dev check chạy đúng các bước kiểm tra tĩnh của máy chủ trên máy bạn. Phải sạch lỗi.
  5. Một lần: tạo token ở https://livebridge.vn/app/dev/cli rồi npx @livebridge/dev login. Sau đó npx @livebridge/dev upload (thêm --test-only để chỉ thử, chưa phát hành; thêm --create nếu game chưa được tạo trên web).
  6. Mỗi lần tải lên phải tăng `version` trong manifest.json (ví dụ 1.0.0 thành 1.0.1).

Các file AGENTS.md, CLAUDE.md, README.md, file ẩn (bắt đầu bằng .) và node_modules không được đưa vào bản tải lên.

SDK LiveBridge

Nạp bằng đúng dòng này (trước script của game). Đừng copy hay bundle SDK: serve tự đổi URL này sang bản chạy cục bộ, còn khi chạy thật nó là bản của LiveBridge.

<script src="https://livebridge.vn/sdk/livebridge.js"></script>
<script>
  const game = new LiveBridgeGame({
    onAction(actionId, event, rule) { /* quà đã được streamer ánh xạ tới hành động của bạn */ },
    onGift(event) { /* MỌI quà, kể cả quà chưa ánh xạ */ },
    onChat(comment, user, event) {},
    onFollow(user, event) {},
    onShare(user, event) {},
    onMember(user, event) {},   // người vào phòng
    onLike(user, event) {},     // event.like.count = số like của lô này
  });
</script>

Tất cả handler (đều tuỳ chọn):

  • onReady(config, actionMap): SDK đã đọc xong manifest và bản ánh xạ quà. config là manifest.json của bạn. `actionMap` có thể là `null` nếu lần đọc đầu thất bại (lỗi mạng, 429): khi đó bản ánh xạ đến sau qua onConfig. Đừng giả định actionMap luôn có.
  • onConfig(actionMap): streamer vừa lưu lại ánh xạ quà (không cần tải lại trang), hoặc bản ánh xạ đến muộn sau onReady.
  • onAction(actionId, event, rule): một quà khớp một quy tắc. rule có actionId, amount (mặc định 1), và giftName hoặc minDiamonds/maxDiamonds.
  • onGift(event): mọi quà. Luôn gọi, kể cả khi onAction cũng gọi.
  • onChat(comment, user, event), onFollow(user, event), onShare(user, event), onMember(user, event), onLike(user, event).
  • onEvent(event): mọi sự kiện thô (cả gift, chat...).
  • onConnect(), onDisconnect(): socket mở / đóng. SDK tự kết nối lại sau vài giây, trừ khi link bị thu hồi.
  • onTikTokStatus("connected" | "connecting" | "ended" | "disconnected"): tình trạng phòng TikTok của streamer. Socket có thể mở trong khi streamer chưa bấm kết nối TikTok.
  • apiOrigin (tuỳ chọn): chỉ cần khi bạn tự host SDK. Đừng dùng.
  • Hàm tiện ích: LiveBridgeGame.resolveGiftAction(actionMap, event), LiveBridgeGame.getDiamonds(event) (= diamondCount x repeatCount), LiveBridgeGame.getUser(event); game.destroy() để dừng.

Hình dạng sự kiện (sau khi lọc quyền riêng tư; trường có thể thiếu thì kiểm tra trước khi dùng):

{ type: "gift", seq, ts, channel,
  user: { id, uniqueId, nickname, avatar, roles?: { moderator, subscriber, follower, member } },
  gift: { id, name, diamondCount, repeatCount, icon? } }          // chat: chat: { comment }
                                                                   // like: like: { count, total? }

gift.icon luôn là "" với game của nhà phát triển (CSP chặn ảnh quà từ CDN TikTok và LiveBridge chưa có proxy cho ảnh quà): tự vẽ biểu tượng quà trong game nếu cần.

Quy tắc ánh xạ quà: tên quà khớp chính xác > khoảng kim cương (diamondCount x repeatCount nằm trong minDiamonds..maxDiamonds) > hành động có actionId là "default". Streamer có thể đổi ánh xạ bất kỳ lúc nào, nên luôn xử lý cả onGift cho quà chưa ánh xạ.

Quyền riêng tư (streamer chọn cho từng game). Mặc định gửi tên và avatar. Khi streamer tắt tên: user.id thành anon-<16 hex>, user.uniqueId thành viewer-<4 hex>, user.nickname thành Viewer #<4 hex>; mỗi người xem luôn nhận cùng một mã trong cùng phòng và game. user.avatar là URL ảnh qua proxy của LiveBridge (https://livebridge.vn/api/avatar?u=<uniqueId>&s=96, CSP cho phép; chưa có ảnh thì proxy trả ảnh mặc định), không bao giờ là URL CDN TikTok. Khi tắt avatar, và cả khi tắt tên (URL proxy chứa tên thật): user.avatar là "". Game phải hiển thị tốt cả hai trường hợp (ví dụ chữ cái đầu thay avatar).

Chế độ token. Game chỉ có ?t=. Không có ?t= thì SDK ở chế độ demo (không kết nối, không lỗi). Link bị thu hồi (streamer bấm "Ngắt game này", đổi tài khoản TikTok, quản trị gỡ game) thì socket đóng với mã 4003: SDK dừng hẳn và gọi onDisconnect; hãy hiện "Link hết hạn, hãy mở lại game từ LiveBridge". window.__LIVEBRIDGE__.status là idle, open, closed hoặc revoked.

Phải tạo `new LiveBridgeGame({...})` ngay khi trang tải, không chờ người dùng bấm. Bộ kiểm tra tự động mở game trong trình duyệt thật và chờ trạng thái open.

manifest.json

JSON Schema: https://livebridge.vn/schemas/game-manifest.json. Quy tắc:

  • id: giống id game đã tạo, ^[a-z0-9-]{3,40}$, không đổi sau khi tạo; không dùng từ dành riêng (admin, api, app, www, sdk, dev, developers, games, static, cdn, mail, livebridge, test) hay id game có sẵn.
  • version: x.y.z, phải lớn hơn bản đang chạy.
  • name, summary, description: mỗi cái có cả vi và en, không rỗng, không từ không phù hợp.
  • platform: "web". connection: { "needsApp": false, "sendUsername": true, "sendAvatar": true } (needsApp luôn false).
  • entry: đường dẫn file HTML chính từ gốc thư mục (phân biệt hoa thường). Game tải lên dùng entry, không dùng url.
  • cover: ảnh bìa 16:9 (ví dụ 1280x720) có trong thư mục. screenshots: tối đa 8 ảnh. tags: tối đa 5.
  • connectOrigins: danh sách nơi game được phép gọi mạng, dạng https://host hoặc wss://host (chữ thường, không có đường dẫn, không dấu *). Mặc định [].
  • actions: các hành động game làm được, mỗi cái { id, name, name_vi, description, description_vi }. defaultGiftMapping: ánh xạ gợi ý, mỗi dòng có hoặc giftName hoặc minDiamonds (kèm maxDiamonds tuỳ chọn), cộng actionId phải có trong actions.

Điều cấm

  • Không gọi mạng ra ngoài connectOrigins (fetch, XHR, WebSocket, ảnh, font ngoài danh sách cho phép ở mục CSP). Cần API riêng thì khai báo origin đó trong connectOrigins.
  • Không lưu hay gửi dữ liệu người xem đi nơi nào khác: tên, avatar, id, bình luận chỉ dùng để hiển thị trong game, không ghi vào localStorage/cookie/IndexedDB/máy chủ riêng, không đưa vào URL.
  • Không hỏi, đọc hay dùng `?key=` hay mã kết nối (room key) của streamer. Game chỉ nhận ?t=.
  • Không giả định bàn phím hay chuột: game được dùng khi streamer livestream, người điều khiển là người xem qua quà và chat.
  • Không dùng dịch vụ phân tích bên ngoài (Google Analytics, Sentry, Mixpanel...) và không nhúng iframe hay script quảng cáo.
  • Dữ liệu người xem là không tin cậy: hiển thị bằng textContent, không bao giờ innerHTML, eval hay document.write với dữ liệu đó.
  • Không có nội dung vi phạm pháp luật, khiêu dâm, bạo lực cực đoan, thù ghét, hay cờ bạc ăn tiền thật. LiveBridge có quyền gỡ game bất cứ lúc nào (xem điều khoản nhà phát triển).
  • Dùng đường dẫn tương đối (game.js, ./img/a.png), không bắt đầu bằng /: game chạy dưới https://<id-game>.<miền sandbox>/v/<version>/.

CSP (chính sách nội dung của sandbox)

Mọi file của game được trả với CSP này; serve áp dụng đúng như vậy để bạn thấy lỗi sớm:

  • default-src 'self'.
  • Script: file của game, /sdk/ của LiveBridge, inline script, WebAssembly ('wasm-unsafe-eval'), và các CDN https://cdnjs.cloudflare.com, https://cdn.jsdelivr.net, https://unpkg.com.
  • Gọi mạng (fetch, XHR, WebSocket): chính game, API LiveBridge, và connectOrigins.
  • Ảnh, âm thanh, video, font: file của game, data:, blob:, API LiveBridge, ba CDN trên và connectOrigins (https). Google Fonts được phép (CSS từ fonts.googleapis.com, font từ fonts.gstatic.com).
  • Web Worker: file của game hoặc blob:. Không có <object>, <base>, <form action>.
  • Game được nhúng trong OBS và dashboard (không có frame-ancestors), nhưng không nhúng trang ngoài.

Cách thử

  • npx @livebridge/dev serve [thư mục] --port 5173. Giả lập đúng các endpoint token của LiveBridge (/api/game-token/actions|status|manifest, /ws?t=lbg_dev) với token giả lbg_dev. Ánh xạ quà lấy từ defaultGiftMapping trong manifest.json (khi streamer thật dùng, họ có thể sửa).
  • Panel http://localhost:5173/__panel: nút quà (danh sách quà TikTok mẫu, nhập số lần), chat, like x N, follow, share, người vào phòng, "người xem ngẫu nhiên" (tên + avatar), công tắc gửi tên / gửi avatar (xem game thấy gì khi streamer tắt), nút "gửi lại config" (thử onConfig).
  • Sau mỗi thay đổi: tải lại trang game, rồi npx @livebridge/dev check.
  • Khi tải lên, LiveBridge còn mở game trong trình duyệt thật với API giả để kiểm tra: trang phải tải xong trong 20 giây, không có lỗi JavaScript chưa bắt, và SDK phải kết nối.

Checklist trước khi tải lên (mã lỗi và cách sửa)

check và upload in lỗi dạng [mã] (trường) kèm "Cách sửa". Cách sửa thường gặp:

  • zip_invalid: nén lại bằng zip thường (không mật khẩu, không rar/7z). CLI tự nén nên hiếm gặp.
  • zip_too_big: game giải nén quá 50 MB. Nén ảnh/âm thanh, xoá file thừa, hoặc tải tài nguyên lớn từ CDN.
  • zip_too_many_files: hơn 2.000 file. Gộp JS/CSS, ghép ảnh thành sprite sheet.
  • zip_path_escape: đường dẫn có .., \ hoặc bắt đầu bằng /. Đổi tên file.
  • zip_symlink: có liên kết tượng trưng. Thay bằng file thật.
  • zip_duplicate: hai file chỉ khác nhau chữ hoa/thường. Đổi tên.
  • manifest_missing: không có manifest.json ở gốc thư mục.
  • manifest_invalid: một trường sai. Đọc tên trường trong lỗi, sửa theo JSON Schema.
  • version_not_newer: version chưa lớn hơn bản đang chạy. Tăng lên.
  • version_exists: số phiên bản này đã được tải lên. Tăng version.
  • entry_missing: entry không trỏ tới file có thật. Sửa đường dẫn (phân biệt hoa thường).
  • cover_missing: thiếu ảnh bìa (hoặc ảnh trong screenshots). Thêm file hoặc sửa đường dẫn.
  • file_type_forbidden: chỉ cho phép html htm js mjs css json png jpg jpeg gif webp avif svg ico mp3 ogg wav m4a mp4 webm woff woff2 ttf otf wasm txt map. Xoá file khác.
  • words_blocked: tên/tóm tắt/mô tả có từ không phù hợp. Viết lại.
  • url_not_https, url_unreachable: dành cho game external_web (tải lên từ web, không qua CLI).
  • smoke_timeout: trang không phản hồi trong 20 giây. Tìm vòng lặp vô hạn hoặc tác vụ nặng lúc tải.
  • smoke_js_error: có lỗi JavaScript khi chạy thử. Mở ?t=lbg_dev, xem Console, sửa lỗi.
  • smoke_sdk_not_connected: SDK không kết nối. Nạp https://livebridge.vn/sdk/livebridge.js và gọi new LiveBridgeGame({...}) ngay khi tải trang.
  • smoke_load_failed: không mở được entry. Kiểm tra entry và file tồn tại.
  • smoke_infra: lỗi phía hệ thống kiểm tra. Tải lại cùng phiên bản sau vài phút, không cần đổi version.
  • sdk_missing (chỉ CLI, chỉ cảnh báo): chưa có file .html nào nạp /sdk/livebridge.js.

Giới hạn: tối đa 10 game mỗi nhà phát triển, 20 lần tải lên mỗi ngày, hệ thống giữ file của 5 phiên bản mới nhất.

Cách đọc một lỗi kiểm tra

Mỗi lỗi có mã, trường (nếu có), một câu mô tả và một câu "Cách sửa" bằng tiếng Việt và tiếng Anh. Làm theo thứ tự: (1) sửa lỗi đầu tiên bằng đúng "Cách sửa"; (2) chạy lại check; (3) lặp lại. Nếu nhà phát triển dán cho bạn đoạn bắt đầu bằng LiveBridge upload check failed for <game> v<version>: (nút Sao chép lỗi cho AI trên web hoặc đoạn cuối của check), đó chính là danh sách lỗi: sửa từng mục.