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

@taole/giftstage

v0.1.21

Published

High-performance WebGPU/WebGL2 gift animation player unifying SVGA, VAP, and AlphaVideo

Readme

GiftStage

统一的 Web 礼物播放框架,支持:

  • SVGA
  • VAP / VAPX
  • 透明视频 AlphaVideo

底层支持:

  • WebGPU
  • WebGL2
  • WebGL1 兼容兜底

适用场景:

  • 直播间礼物
  • 大批同屏动画
  • 需要统一接入 SVGA / VAP / 透明视频 的业务场景

npm 包信息

  • 包名:@taole/giftstage
  • npm:npm i @taole/giftstage
  • ESM 导入:
import { GiftStage } from '@taole/giftstage';
  • CommonJS 导入:
const { GiftStage } = require('@taole/giftstage');

特性

  • 统一 API:addGift() 即可播放三类礼物
  • SVGA 支持 Worker 解析、atlas 缓存、slot 替换
  • VAP / AlphaVideo 支持实验性的 WebCodecs 和稳定的 HTMLVideoElement 双路径
  • 同源视频播放实例、纹理、资源复用
  • 内存 LRU 缓存,默认 128MB
  • IndexedDB 磁盘 LRU 缓存,默认 2048MB
  • x / y 支持百分比定位
  • width / height 支持按礼物原始尺寸自动补全

安装

npm install

安装发布包:

npm i @taole/giftstage

开发

npm run dev

构建

npm run build

Demo 构建:

npm run build:demo

快速开始

import { GiftStage } from '@taole/giftstage';

const container = document.getElementById('app')!;

const stage = new GiftStage({
  container,
  preferWebGPU: true,
});

await stage.ready;

await stage.addGift({
  type: 'svga',
  source: 'https://example.com/demo.svga',
  x: 100,
  y: 100,
  loop: 0,
});

核心 API

new GiftStage(options)

创建礼物舞台。

常用配置:

  • container: HTMLElement 挂载容器。

  • resolution?: number 指定 canvas backing store 分辨率倍率。默认跟随 devicePixelRatio

  • antialias?: boolean 是否开启抗锯齿。

  • preferWebGPU?: boolean 是否优先使用 WebGPU

  • forceWebGL1?: boolean 强制走 WebGL1,用于兼容性验证。

  • preferWebCodecs?: boolean 实验性特性。默认关闭;显式传 true 时才会尝试用 WebCodecs 播放 VAP / AlphaVideo

  • shareIdenticalVideoPlayback?: boolean 是否复用近同时起播的同源视频播放实例。默认开启。

  • sharedVideoPlaybackWindowMs?: number 同源视频共享播放窗口,默认 100ms

  • webCodecsVideoAtlas?: { width: number; height: number } 实验性 WebCodecs 视频共享 atlas 配置。

  • webCodecsDecodeInWorker?: boolean 实验性 WebCodecs 选项,控制是否在 Worker 中执行解码。

  • webCodecsMaxDecodedFrames?: number 实验性 WebCodecs 选项,控制保留的最大解码帧数。

  • webCodecsDecodeAheadFrames?: number 实验性 WebCodecs 选项,控制前向解码帧数。

  • svgaParseInWorker?: boolean 是否在 Worker 中解析 SVGA。

  • maxConcurrentParse?: number 资源下载 / 解析 / 图像解码的并发数。 不传时自动跟随 navigator.hardwareConcurrency

  • onError?: (error: Error) => void 统一错误回调。

await stage.ready

等待底层后端和运行环境初始化完成。建议在第一次 addGift() 前等待。

stage.addGift(options)

插入一个礼物,返回:

Promise<GiftHandle>;

GiftHandle API

addGift() 返回的句柄可用于控制单个礼物:

  • gift.id
  • gift.type
  • gift.pause()
  • gift.resume()
  • gift.destroy()
    • 立即移除当前礼物
  • gift.animate(stepOrSteps?)
    • 创建链式动画并返回 GiftAnimationChain

GiftAnimationChain 支持:

  • .to(step) / .then(step)
    • 追加动画步骤(两者等价)
  • .delay(milliseconds)
    • 在链中插入等待,不改变位置、缩放和透明度
  • .onComplete((gift) => void)
    • 整条链执行完成后的回调
  • .start(mode?)
    • mode: 'immediate' | 'afterGiftComplete'
    • immediate:立即开始(默认)
    • afterGiftComplete:等待礼物主播放结束后再执行链
  • .cancel()
    • 取消当前礼物正在执行的链式动画

stage.removeGift(id)

按 ID 移除礼物。

stage.removeAll()

移除全部礼物。

stage.pause()

暂停舞台。

stage.resume()

恢复舞台。

stage.destroy()

销毁舞台并释放资源。

addGift() 参数

通用参数

  • type: 'svga' | 'vap' | 'alphaVideo'
  • source: string | ArrayBuffer
  • x: number | \${number}%``
  • y: number | \${number}%``
  • zIndex?: number
  • width?: number
  • height?: number
  • useOriginalSize?: boolean
  • objectFit?: 'contain' | 'cover' | 'fill'
  • loop?: number
    • 0 表示无限循环
  • opacity?: number
    • 全局透明度,范围 0 ~ 1,默认 1
  • clearsAfterStop?: boolean
    • 播放结束后,是否自动移除礼物
    • 默认 true,传 false 时会停留最后一帧,方便后续继续调用 gift.animate(...).start()
  • mute?: boolean
  • onComplete?: (gift) => void

层级规则:

  • zIndexSVGA / VAP / AlphaVideo 三种礼物间通用
  • 数值越大,渲染越靠上
  • 同层级下,后 addGift() 的礼物会覆盖先添加的礼物

宽高默认行为

width / height 现在是可选参数,规则如下:

  • 两个都传:按传入值显示
  • 只传 widthheight 按礼物原始宽高比自动补全
  • 只传 heightwidth 按礼物原始宽高比自动补全
  • 两个都不传:默认按当前画布尺寸做等比 contain
  • 如果 objectFit: 'cover' 且两个都不传:按整个画布作为显示区域做等比 cover
  • 也就是会在画布内尽可能放大或缩小,并保持礼物原始宽高比
  • 如果 useOriginalSize: true,且礼物原始尺寸本身小于画布,则优先使用礼物原始尺寸
  • 如果 useOriginalSize: true,但礼物原始尺寸超出画布,则仍会按画布尺寸等比缩小

例如:

await stage.addGift({
  type: 'svga',
  source: 'https://example.com/demo.svga',
  x: '50%',
  y: '50%',
  loop: 0,
});

这时会按舞台尺寸做等比适配,并保持礼物原始宽高比。

如果希望礼物铺满整个画布,并按中心裁剪超出的部分,可以使用 cover

await stage.addGift({
  type: 'svga',
  source: 'https://example.com/demo.svga',
  x: '50%',
  y: '50%',
  objectFit: 'cover',
  loop: 0,
});

x: '50%'y: '50%' 且未传 width / height 时,显示区域会居中放在整个画布上;cover 会保持礼物原始宽高比铺满该区域,并从中心裁剪溢出的部分。

如果你希望“小礼物保持原始尺寸,大礼物再缩小”,可以这样:

await stage.addGift({
  type: 'svga',
  source: 'https://example.com/demo.svga',
  x: '50%',
  y: '50%',
  useOriginalSize: true,
  loop: 0,
});

百分比坐标

x / y 支持百分比,例如:

await stage.addGift({
  type: 'svga',
  source: 'https://example.com/demo.svga',
  x: '50%',
  y: '50%',
  width: 300,
  height: 300,
  loop: 0,
});

语义是:

  • x: '50%' 按容器宽度的 50% 定位,并减去自身一半宽度
  • y: '50%' 按容器高度的 50% 定位,并减去自身一半高度

也就是接近:

left: 50%;
top: 50%;
transform: translate(-50%, -50%);

如果是数值,则继续按原来的像素坐标语义处理。

三类礼物示例

播放 SVGA

await stage.addGift({
  type: 'svga',
  source: 'https://example.com/demo.svga',
  x: 20,
  y: 20,
  width: 300,
  height: 300,
  loop: 1,
});

播放 VAP

await stage.addGift({
  type: 'vap',
  source: 'https://example.com/demo.mp4',
  config: 'https://example.com/demo.json',
  x: 20,
  y: 20,
  width: 400,
  height: 220,
  loop: 0,
});

播放透明视频

await stage.addGift({
  type: 'alphaVideo',
  source: 'https://example.com/demo.mp4',
  x: 20,
  y: 20,
  width: 400,
  height: 220,
  loop: 0,
});

动画控制

链式动画

addGift() 返回的 GiftHandle 支持 animate()。一次 to() 是组合动画,同一步里可以同时移动、缩放和改变透明度;多个 to() / then() 会按顺序播放:

const gift = await stage.addGift({
  type: 'svga',
  source: 'https://example.com/demo.svga',
  x: '50%',
  y: '50%',
  width: 300,
  height: 300,
  loop: 0,
});

await gift
  .animate()
  .to({
    flyTo: { x: 200, y: 240 },
    scaleTo: 0.8,
    opacity: 0.6,
    duration: 500,
  })
  .then({
    flyTo: { x: 600, y: 320 },
    scaleTo: 1.1,
    opacity: 1,
    duration: 700,
  })
  .delay(300)
  .then({
    opacity: 0,
    duration: 400,
  })
  .onComplete((g) => {
    console.log('chain complete', g.id);
  })
  .start();

也可以传入单步或数组:

gift.animate({ flyTo: { x: 300, y: 300 }, scaleTo: 0.5, opacity: 0.3 }).start();

gift
  .animate([
    { flyTo: { x: 300, y: 300 }, duration: 400 },
    { scaleTo: 1, opacity: 1, duration: 300 },
  ])
  .start();

Slot 替换

SVGA

使用 svgaSlots

await stage.addGift({
  type: 'svga',
  source: 'https://example.com/demo.svga',
  x: 0,
  y: 0,
  width: 400,
  height: 400,
  svgaSlots: {
    avatar: { image: avatarImage },
    title: {
      text: 'Hello',
      color: '#ff0000',
      fontSize: 28,
      mode: 'dynamic',
    },
  },
});

支持:

  • TexImageSource
  • 文本配置
  • 图片配置

SVGA 文本配置会按目标 frame 自动适配字号,避免文字超出槽位:

  • mode: 'dynamic':默认行为。生成文字自身尺寸的纹理,渲染时按自身逻辑尺寸居中到 frame 内,不会被拉伸。
  • mode: 'replace':生成和 frame 一样大的纹理,按替换图逻辑铺满 frame。
  • fontSize?: number:期望字号;如果文字放不下,会自动缩小。
  • minFontSize?: number / maxFontSize?: number:限制自适应字号范围。
  • padding?: number:文字纹理内边距,默认 2
  • scale?: number:文字纹理栅格倍率,SVGA 默认 3,用于保持清晰度。
  • fontStyle?: string | { font?: string; color?: string }:字体样式,SVGA / VAP 都支持。

fontStyle 可以直接传 canvas font 字符串:

svgaSlots: {
  title: {
    text: 'Hello',
    fontStyle: 'bold 40px Arial',
  },
}

也可以传对象:

vapSlots: {
  welcome01: {
    text: '欢迎进入房间',
    fontStyle: {
      font: 'bold 40px Arial',
      color: '#ffffff',
    },
  },
}

对象形式目前生效字段是 fontcolor。如果同时传了外层 colorfontStyle.color,以 fontStyle.color 为准。VAP 文本如果没有传 fontStyle,会回退使用 VAP 配置里的 src.fontStyle

VAP / VAPX

使用 vapSlots

await stage.addGift({
  type: 'vap',
  source: 'https://example.com/demo.mp4',
  config: 'https://example.com/demo.json',
  x: 0,
  y: 0,
  width: 400,
  height: 400,
  vapSlots: {
    welcome01: '欢迎进入房间',
    avatar_left: 'https://example.com/avatar.png',
  },
});

支持:

  • 文本字符串
  • 图片 URL
  • TexImageSource
  • 结构化文本 / 图片对象

后端策略

默认回退顺序:

  1. WebGPU
  2. WebGL2
  3. WebGL1

说明:

  • WebGPU 仅在浏览器支持相关必要能力时启用
  • WebGL1 主要用于兼容兜底,不以性能最优为目标
  • demo 中可手动强制切换到 WebGL1

缓存策略

内存缓存

  • 默认 128MB
  • LRU 淘汰

缓存内容包括:

  • 原始资源字节
  • 文本 / JSON
  • SVGA worker payload
  • SVGA atlas 资产

IndexedDB 磁盘缓存

  • 默认 2048MB
  • LRU 淘汰
  • 读取命中会刷新最近访问时间
  • 超出预算时按最久未使用记录淘汰

异常情况处理:

  • IndexedDB 不可用、事务失败、写入失败、容量不足时,会自动降级
  • 损坏的 SVGA 磁盘缓存会自动删除并重新生成

项目结构

主要目录:

  • src/ 核心源码
  • docs/ 设计与汇总文档
  • publish/ 发布脚本
  • static/ demo 依赖资源
  • tests/ 测试

对外导出

入口文件:

主要导出:

  • GiftStage
  • createBackend
  • WebGPUBackend
  • WebGL2Backend
  • WebGL1Backend
  • parseSVGA
  • buildAtlas
  • parseVAPConfig
  • 相关类型定义

Demo

Demo 入口:

可用于验证:

  • SVGA / VAP / AlphaVideo 播放
  • slot 替换
  • WebGPU / WebGL2 / WebGL1 切换
  • 大批同屏压测

相关文档