Skip to content

基本用法 ​

创建实例 ​

方式一:直接传 modelPath ​

ts
import { Live2DSprite } from 'easy-live2d'

const sprite = new Live2DSprite({
  modelPath: '/Resources/Hiyori/Hiyori.model3.json',
})

方式二:先创建,再 init() ​

ts
const sprite = new Live2DSprite()

sprite.init({
  modelPath: '/Resources/Hiyori/Hiyori.model3.json',
  draggable: true,
})

方式三:使用 CubismSetting ​

ts
import { CubismSetting, Live2DSprite } from 'easy-live2d'

const modelJSON = await fetch('/Resources/Hiyori/Hiyori.model3.json').then(r => r.json())

const modelSetting = new CubismSetting({
  modelJSON,
  prefixPath: '/Resources/Hiyori/',
})

// 可选:重写资源路径(优先级高于 prefixPath)
modelSetting.redirectPath(({ file }) => {
  return `https://cdn.example.com/live2d/hiyori/${file}`
})

const sprite = new Live2DSprite({
  modelSetting,
})

modelPath 和 modelSetting 至少提供一个。两者同时存在时优先使用 modelPath。

加入 Pixi 场景 ​

ts
import { Application } from 'pixi.js'

const canvas = document.getElementById('live2d') as HTMLCanvasElement
const app = new Application()

await app.init({
  canvas,
  backgroundAlpha: 0,
  autoDensity: true,
  resolution: Math.max(window.devicePixelRatio || 1, 1),
})

sprite.width = canvas.clientWidth
app.stage.addChild(sprite)

Live2DSprite 继承自 Pixi Sprite,支持所有标准属性:

ts
sprite.x = 40
sprite.y = -80
sprite.anchor.set(0.5)
sprite.scale.set(0.8)

Pixi 默认使用 WebGL 2,无需额外渲染选项或 ticker。模型跟随 Pixi 渲染更新;首帧间隔为 0,长暂停后单次最多推进 100ms。

监听模型就绪 ​

模型完成内部初始化后触发 ready 事件:

ts
sprite.onLive2D('ready', () => {
  console.log('模型已就绪')
  console.log(sprite.getModelCanvasSize())
})

获取模型原始尺寸、播放首个动作等依赖模型状态的操作,应放在 ready 回调中。

TIP

在 ready 之前调用 startMotion()、setExpression()、playVoice() 等方法时,请求会自动排队,待模型初始化完成后执行。

ts
import { Priority } from 'easy-live2d'

try {
  await sprite.ready
  await sprite.startMotion({ group: 'TapBody', no: 0, priority: Priority.Normal })
} catch (error) {
  console.error('模型初始化或动作加载失败', error)
}

初始化失败(包括不支持的 Core/上下文或已声明资源不可用)会拒绝该 Promise;就绪前销毁也会拒绝,初始化失败后不逐帧重试。若 Pixi 设置了 autoStart: false,应在加入舞台后先调用 app.render() 再等待就绪。同步 ready 回调异常会记录日志但不释放已加载模型;异步回调的 rejection 需在回调内自行捕获。

就绪前入队的调用不等待实际播放。需要获知执行结果时,请先等待 sprite.ready。

点击命中区域 ​

ts
import { Priority } from 'easy-live2d'

sprite.onLive2D('hit', async ({ hitAreaName, x, y }) => {
  console.log('命中区域:', hitAreaName, x, y)

  if (hitAreaName === 'Head') {
    await sprite.startMotion({
      group: 'TapBody',
      no: 0,
      priority: Priority.Force,
    })
  }
})
  • hitAreaName 来自模型 HitAreas 配置。
  • x、y 是变换后的模型视图坐标,不是 DOM 像素坐标。

拖拽模型 ​

ts
const sprite = new Live2DSprite({
  modelPath: '/Resources/Hiyori/Hiyori.model3.json',
  draggable: true,
})

sprite.onLive2D('dragStart', ({ x, y }) => {
  console.log('开始拖拽', x, y)
})

sprite.onLive2D('dragMove', ({ x, y, deltaX, deltaY }) => {
  console.log('拖拽中', x, y, deltaX, deltaY)
})

sprite.onLive2D('dragEnd', ({ x, y }) => {
  console.log('拖拽结束', x, y)
})
  • 需要 draggable: true 才会触发拖拽事件。
  • 拖拽事件中的 x、y 是精灵位置,不是指针坐标。

播放动作 ​

ts
import { Priority } from 'easy-live2d'

// 播放指定动作
await sprite.startMotion({
  group: 'TapBody',
  no: 0,
  priority: Priority.Normal,
})

// 随机播放
await sprite.startRandomMotion({
  group: 'TapBody',
  priority: Priority.Normal,
})

Priority 枚举值:

值说明
Priority.None不主动抢占
Priority.Idle空闲动作
Priority.Normal普通动作
Priority.Force强制打断当前动作

动作结束后会自动回落到 Config.MotionGroupIdle 指定的 idle 动作组。

切换表情 ​

ts
// 通过 expressionId
sprite.setExpression({ expressionId: 'smile' })

// 通过 index
sprite.setExpression({ index: 0 })

sprite.setRandomExpression()

expressionId 或 index 不存在时会在控制台输出警告。

语音与口型同步 ​

ts
// 播放语音
await sprite.playVoice({
  voicePath: '/Resources/Hiyori/sounds/test.wav',
})

// immediate: true 会先停止当前语音再播放
await sprite.playVoice({
  voicePath: '/Resources/Hiyori/sounds/test.mp3',
  immediate: true,
})

// 停止语音
sprite.stopVoice()
  • 语音解码使用 Web Audio decodeAudioData,支持浏览器可解码的音频格式(wav、mp3、ogg 等)。
  • 口型同步依赖模型中配置的 LipSync 参数映射。

语音按精灵隔离,停止或销毁会取消待完成语音操作,不打断其他精灵;immediate: false 保留本精灵已开始播放的语音。播放和口型共用一次下载、解码,完成与失败行为见 语音 API。

尺寸控制 ​

ts
// 直接设置宽高
sprite.width = 420
sprite.height = 760

// 通过 setSize 设置
sprite.setSize(420, 760)

// 获取尺寸
const size = sprite.getSize()

// 获取模型原始画布尺寸
const canvasSize = sprite.getModelCanvasSize()
// => { width, height, pixelsPerUnit } | null

width / height 可以在模型加载前设置,内部会在初始化完成后自动应用。

全局配置 ​

ts
import { Config, LogLevel } from 'easy-live2d'

Config.MotionGroupIdle = 'Idle'
Config.MouseFollow = true
Config.DebugTouchLogEnable = false
Config.CubismLoggingLevel = LogLevel.LogLevel_Warning

常用配置项:

字段默认值说明
MotionGroupIdle'Idle'动作结束后回落的 idle 动作组
MouseFollowtrue模型是否跟随鼠标移动
MotionSoundtrue是否在 startMotion 时自动播放动作绑定的音效
DebugLogEnabletrue是否启用 Cubism 日志
DebugTouchLogEnablefalse是否输出点击坐标日志
CubismLoggingLevelLogLevel_VerboseCubism Framework 日志级别
MOCConsistencyValidationEnabletrue是否开启 moc 一致性校验

使用 Config.resetConfig() 可恢复所有默认值。

驱动参数控制 ​

ts
// 通过参数 ID 设置驱动参数值(持久生效,每帧自动重新写入)
sprite.setParameterValueById('ParamAngleX', 15.0)

// 带混合权重
sprite.setParameterValueById('ParamMouthOpenY', 1.0, 0.8)

// 通过参数索引设置驱动参数值
sprite.setParameterValueByIndex(0, 0.5)

// 通过参数 ID 获取驱动参数的取值范围
const range = sprite.getParameterValueRangeById('ParamAngleX')
// range => { min: -30, max: 30 }

// 通过参数索引获取驱动参数的取值范围
const rangeByIndex = sprite.getParameterValueRangeByIndex(0)
// rangeByIndex => { min: -30, max: 30 }
  • setParameterValueById / setParameterValueByIndex 设置的值会持久生效——每帧渲染时均自动重新写入,无需每帧手动调用。
  • ready 前调用会自动排队,待模型初始化完成后执行。
  • getParameterValueRangeById / getParameterValueRangeByIndex 模型未就绪或参数不存在时返回 null。

释放资源 ​

ts
sprite.destroy()

销毁时会清理指针事件监听、ResizeObserver、WebGL 纹理缓存、Live2D 上下文和 Cubism 生命周期。在 Vue、React 等框架中应在组件卸载时调用。

重复销毁安全;加载中销毁会拒绝待完成的 ready 并取消请求。最后一个存活/加载实例结束前,共享 Framework 保持可用。宿主不再需要 Pixi Application 时,应另外销毁 Application。

多实例 ​

每个 Live2DSprite 持有独立的上下文和事件总线,支持在同一个 Pixi 场景中创建多个实例:

ts
const spriteA = new Live2DSprite({
  modelPath: '/Resources/Hiyori/Hiyori.model3.json',
})

const spriteB = new Live2DSprite({
  modelPath: '/Resources/Mark/Mark.model3.json',
})

spriteA.width = 300
spriteB.width = 300
spriteB.x = 400

app.stage.addChild(spriteA)
app.stage.addChild(spriteB)

Released under the MIT License