npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@wanlingsdk/avatar-sdk

v0.1.10

Published

Wanling Avatar SDK - 虚拟人视频播放SDK,支持WebCodecs解码、音视频同步、实时语音对话

Readme

WanLing Avatar SDK

基于预渲染动作视频的虚拟人SDK,适合快速集成、低性能要求的场景。

特性

  • 🎬 预渲染视频播放:支持 HTML5 Video 或 Canvas 渲染两种模式
  • 🚀 0 闪屏连播:Canvas 模式使用 WebCodecs + mp4box.js 自解码自渲染,连播切换无闪烁
  • 🎭 动作管理:支持idle、talk、wave、laugh等多种动作
  • 🔄 无缝转场:支持fade、cut、blend等转场效果
  • 📦 轻量级:无3D引擎依赖,纯JavaScript实现
  • 🌐 跨平台:支持H5、iOS、Android(通过WebView)
  • 📡 单流编排:与后端「单条流 + 按帧 append」对齐;avatar_datavideo_sequencestream_seqstream_seq=0 表示首包/清空后写入,stream_seq>0 表示追加到当前段列表,前端按 currentFrame 在段列表中选段播放。

文档

快速开始

安装

# 通过npm安装(待发布)
npm install @xhuman/video-sdk

# 或直接引入dist文件
<script src="https://cdn.example.com/xhuman-video-sdk.js"></script>

基础使用

<!DOCTYPE html>
<html>
<head>
    <title>XHuman Video Avatar Demo</title>
</head>
<body>
    <div id="avatar-container"></div>
    <input type="text" id="text-input" placeholder="输入消息...">
    <button id="send-btn">发送</button>
    
    <script src="./dist/xhuman-video-sdk.js"></script>
    <script>
        const avatar = new XHumanVideoSDK.VideoAvatar({
            apiBaseUrl: 'http://localhost:8000',
            characterId: 'default',
            container: document.getElementById('avatar-container'),
            autoplay: true
        });
        
        // 初始化
        avatar.init().then(() => {
            console.log('Avatar初始化成功');
        });
        
        // 发送消息
        document.getElementById('send-btn').addEventListener('click', async () => {
            const text = document.getElementById('text-input').value;
            const sessionId = 'session_' + Date.now();
            const result = await avatar.sendText(text, sessionId);
            console.log('AI回复:', result.reply_text);
        });
    </script>
</body>
</html>

API文档

VideoAvatar类

构造函数

const avatar = new VideoAvatar(config)

参数

  • apiBaseUrl (string): 后端API地址,默认 http://localhost:8000
  • characterId (string): 虚拟人角色ID
  • container (HTMLElement): 视频容器DOM元素
  • autoplay (boolean): 是否自动播放,默认 true
  • loop (boolean): 是否循环播放,默认 false
  • useCanvasPlayer (boolean): 是否使用 Canvas 播放器(WebCodecs 解码、Canvas 渲染),实现 0 闪屏连播,默认 false
// 启用 Canvas 播放器(需浏览器支持 WebCodecs)
const avatar = new VideoAvatar({
    container: document.getElementById('avatar-container'),
    useCanvasPlayer: true  // 连播切换时无闪屏、无抖动
});

方法

init()

初始化Avatar,预加载基础动作视频。

await avatar.init();
sendText(text, sessionId)

发送文本消息,获取AI回复和对应的动作视频。

const result = await avatar.sendText('你好', 'session_123');
// result: { success, reply_text, avatar_data, audio_base64 }
playAction(actionData)

手动播放指定动作。

await avatar.playAction({
    action: 'wave',
    video_url: 'https://...',
    transition: 'fade',
    duration: 2.0
});
setAction(action)

快速设置动作(使用预加载的视频)。

avatar.setAction('idle'); // 播放idle动作
avatar.setAction('talk'); // 播放talk动作
connectTtsaSocket(options)

连接 TTSA 风格 WebSocket,接收 avatar_data / tts_audio 等。可选 onReadyonError 等回调。

数据晚到与错误码:当身体或音频数据晚于当前播放帧到达时,会通过 options.onError(err) 上报,数据仍会入队使用(身体段照常写入;音频会对齐 sf/ef 后入队以减轻音画错位)。错误对象格式:{ code, message, currentFrame?, sf?, delta? }

  • BODY_DATA_EXPIRED:身体数据晚到(当前帧 > 数据起始帧且 > 10)。
  • AUDIO_DATA_EXPIRED:音频数据晚到(当前帧 > 该块 sf),并自动做 sf/ef 对齐。
avatar.connectTtsaSocket({
    url: 'http://localhost:8000',
    room: 'room_1',
    onReady: () => console.log('时钟已启动'),
    onError: (err) => {
        if (err.code === 'BODY_DATA_EXPIRED' || err.code === 'AUDIO_DATA_EXPIRED') {
            console.warn('数据晚到', err.code, err);
        } else {
            console.error('TTSA 错误', err);
        }
    }
});

外部数据通讯(页面 ↔ SDK)

SDK 提供统一的「接收页面数据」与「对外发送数据」接口,便于与宿主页面、大屏、H5 等多端联动。

接收页面数据(页面 → SDK)

  • setPageData(data):页面将当前上下文写入 SDK(如选中城市、用户 ID、大屏状态)。会与已有数据合并,发送文本时若后端支持可随 send_text 携带 page_data
  • getPageData():获取当前缓存的页面数据副本。
// 页面传入上下文(如大屏选中的城市)
avatar.setPageData({ selectedCity: '乌鲁木齐', scene: 'pc' });
const data = avatar.getPageData(); // { selectedCity: '乌鲁木齐', scene: 'pc' }

对外发送数据(SDK → 页面)

connectTtsaSocket(options) 中传入 onDataOut 回调,SDK 在关键节点推送数据,格式为 { type, payload }

| type | 说明 | payload 示例 | |------|------|--------------| | reply_final | 回复文本流结束 | { text, sessionId, is_final: true } | | state_change | 状态变更 | 服务端下发的 state 数据 | | error | 错误 | { code, message } | | interrupt | 服务端打断 | 打断事件数据 | | sleep_state_change | 沉睡/唤醒状态变更 | { isSleeping, message } | | visibility_change | 展示状态变更 | { visible, interaction_enabled } | | broadcast_start | 播报开始 | { broadcast, queued_count } | | broadcast_end | 播报结束 | { broadcast, reason, message } | | broadcast_interrupted | 播报被打断 | { broadcast, reason, message } | | broadcast_rejected | 播报被拒绝 | { broadcast, reason, message } | | broadcast_queue_cleared | 播报队列已清空 | { reason, message, cleared } | | broadcast_queue_change | 播报队列变化 | { current_context, active_broadcast, queued_count, queue } |

avatar.connectTtsaSocket({
    url: 'http://localhost:8000',
    room: 'room_1',
    onDataOut: ({ type, payload }) => {
        if (type === 'reply_final') console.log('回复完成', payload.text);
        if (type === 'broadcast_start') console.log('播报开始', payload.broadcast?.id);
        if (type === 'error') console.error('SDK 错误', payload);
    },
    onReady: () => console.log('时钟已启动'),
    onError: (err) => console.warn('TTSA 错误', err)
});

主动播报

SDK 提供独立的播报能力,具体业务何时调用由宿主页面决定。播报与聊天互斥:

  • 聊天期间发起播报:自动打断聊天并切入播报
  • 播报期间收到文本/语音:自动终止当前播报并切回聊天
  • 播报内部支持优先级、队列和抢占
const broadcastId = avatar.broadcast({
    text: '前方路段拥堵,请注意绕行',
    priority: 80,
    interrupt: true,
    enqueue: true,
    source: 'biz_warning',
    metadata: { eventId: 'evt_001' }
});

avatar.cancelBroadcast(broadcastId); // 取消指定播报
avatar.cancelBroadcast();            // 取消当前活动播报
avatar.clearBroadcastQueue();        // 清空等待中的播报队列

const state = avatar.getBroadcastState();
console.log(state.currentContext, state.queuedCount);

连接心跳与断连检测

SDK 当前维护两条实时连接:

  • SocketClient:基于 socket.io-client,使用协议内建 heartbeat
  • AsrStreamClient:原生 WebSocket,使用业务层 ping/pong

Socket.IO 链路无需业务方额外发心跳,只需监听连接状态事件即可:

  • connect
  • disconnect
  • reconnect_attempt
  • reconnect_failed

AsrStreamClient 已内置心跳检测:

  • 默认每 2s 发送一次 ping:<timestamp>
  • 服务端返回 pong:<client_ts>:<server_ts_ms>
  • 连续一段时间未收到 pong 时,状态先进入 degraded
  • 超过 3 个心跳周期未收到 pong 且没有任何服务端入站消息时,触发 onError({ code: 'WS_HEARTBEAT_TIMEOUT' })
  • 连接关闭后会自动重连,默认重连间隔 1s

可选配置:

const asr = new AsrStreamClient({
    sessionId: 'room_1',
    baseUrl: 'http://localhost:8000',
    heartbeatIntervalMs: 2000,
    heartbeatTimeoutMs: 6000,
    reconnect: true,
    reconnectDelayMs: 1000,
    reconnectAttempts: Infinity,
    onStatusChange: (status) => {
        console.log('ASR status:', status);
    }
});

onStatusChange 可能收到的心跳相关状态:

  • connecting
  • connected
  • listening
  • degraded
  • heartbeat_ok
  • timeout
  • reconnecting
  • stopped

动作列表

  • idle: 待机动作(默认循环播放)
  • talk: 说话动作(配合TTS音频)
  • wave: 挥手动作(打招呼/告别)
  • nod: 点头动作(同意/理解)
  • think: 思考动作(AI思考中)
  • laugh: 大笑动作(开心/幽默)
  • surprised: 惊讶动作(意外/惊喜)

项目结构

SDK-video/
├── src/
│   ├── index.js           # SDK入口
│   ├── VideoAvatar.js     # 核心类(编排走 WebSocket)
│   ├── CanvasVideoPlayer.js # 唯一播放器(WebCodecs+mp4box+Canvas)
│   └── TtsaSocketClient.js  # Socket.IO 客户端(TTSA 协议)
├── examples/
│   ├── basic/            # 基础示例
│   └── advanced/         # 高级示例
├── dist/                 # 构建产物
└── docs/                 # 文档

开发

# 安装依赖
npm install

# 开发模式
npm run dev

# 构建
npm run build

许可证

MIT License