Making Live2D integration easier! A lightweight, developer-friendly Live2D Web SDK wrapper library based on Pixi.js.
Make your Live2D as easy to control as a pixi sprite!
English | 中文
You can directly experience the charm of easy-live2d in your browser using this cloud IDE StackBlitz! 😋
👉 easy-live2d Official Documentation
easy-live2d wraps Live2D models as Pixi.js Sprite objects, providing a compact API for model loading, hit detection, dragging, motions, expressions, voice playback, and lip sync.
Public exports:
Live2DSprite— Core class, extends PixiSpriteConfig— Global runtime configurationCubismSetting— Manual model config with path redirectionPriority— Motion priority enumLogLevel— Cubism log level enum
pnpm add easy-live2d pixi.js
# or
npm install easy-live2d pixi.js
# or
yarn add easy-live2d pixi.js- Download and load the official
live2dcubismcore.js(Live2D Cubism SDK for Web) in your entry HTML - Browser environment (not SSR)
- An accessible Live2D
model3.json
<script src="/Core/live2dcubismcore.js"></script><!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>easy-live2d</title>
<style>
html,
body {
margin: 0;
width: 100%;
height: 100%;
}
#live2d {
display: block;
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="live2d"></canvas>
<script src="/Core/live2dcubismcore.js"></script>
<script type="module">
import { Application, Ticker } from 'pixi.js'
import { Config, Live2DSprite, Priority } from 'easy-live2d'
Config.MotionGroupIdle = 'Idle'
Config.MouseFollow = true
const canvas = document.getElementById('live2d')
const app = new Application()
await app.init({
canvas,
backgroundAlpha: 0,
autoDensity: true,
resolution: Math.max(window.devicePixelRatio || 1, 1),
})
const sprite = new Live2DSprite({
modelPath: '/Resources/Hiyori/Hiyori.model3.json',
ticker: Ticker.shared,
})
sprite.width = canvas.clientWidth
app.stage.addChild(sprite)
// Option 1: event callback (existing API)
sprite.onLive2D('ready', async () => {
await sprite.startMotion({
group: 'TapBody',
no: 0,
priority: Priority.Normal,
})
})
// Option 2: async/await (new API)
// await sprite.ready
// await sprite.startMotion({ group: 'TapBody', no: 0, priority: Priority.Normal })
</script>
</body>
</html>import { Config, CubismSetting, Live2DSprite, LogLevel, Priority } from 'easy-live2d'
Config.CubismLoggingLevel = LogLevel.LogLevel_Warning
// Disable automatic sound playback for motions (enabled by default)
// Config.MotionSound = false
// Configure crossOrigin for WebGL texture loading.
// Default is "anonymous", which works for most CDN scenarios.
// Set to "use-credentials" if your server requires credentials.
// Set to undefined to disable (not recommended for cross-origin assets).
// The server must respond with a valid Access-Control-Allow-Origin header.
Config.crossOrigin = 'anonymous'
const sprite = new Live2DSprite({
modelPath: '/Resources/Hiyori/Hiyori.model3.json',
draggable: true,
})
// Hit detection
sprite.onLive2D('hit', ({ hitAreaName }) => {
console.log(hitAreaName)
})
// Drag events
sprite.onLive2D('dragMove', ({ x, y }) => {
console.log(x, y)
})
// Motions
await sprite.startMotion({
group: 'TapBody',
no: 0,
priority: Priority.Force,
})
// Expressions (by expressionId)
sprite.setExpression({ expressionId: 'smile' })
// Expressions (by index)
sprite.setExpression({ index: 0 })
// Voice with lip sync
await sprite.playVoice({
voicePath: '/Resources/Hiyori/sounds/test.mp3',
})
// Get all available motions
const motions = sprite.getMotions()
// => [{ group: 'Idle', no: 0, name: 'Idle_0' }, { group: 'TapBody', no: 0, name: 'TapBody_0' }, ...]
// Get all available expressions
const expressions = sprite.getExpressions()
// => [{ name: 'smile' }, { name: 'angry' }, ...]
// Set a parameter value by ID (persists across frames — re-applied every render cycle)
sprite.setParameterValueById('ParamAngleX', 15.0)
sprite.setParameterValueById('ParamMouthOpenY', 1.0, 0.8) // with blend weight
// Set a parameter value by index
sprite.setParameterValueByIndex(0, 0.5)
// Get the value range of a parameter by ID / index
const range = sprite.getParameterValueRangeById('ParamAngleX')
// range => { min: -30, max: 30 }
const rangeByIndex = sprite.getParameterValueRangeByIndex(0)
// rangeByIndex => { min: -30, max: 30 }Voice decoding uses Web Audio decodeAudioData(), supporting any browser-decodable audio format (wav, mp3, ogg, etc.). Lip sync requires LipSync parameter mapping in the model.
If you want to develop or contribute to this project locally:
- Clone the repository with submodules:
git clone --recursive https://github.com/Panzer-Jack/easy-live2d.gitIf you've already cloned without --recursive, initialize the submodule manually:
git submodule update --init --recursiveThis will pull packages/cubism/Framework (the Cubism Web Framework).
- Go to Live2D Cubism SDK for Web and download the SDK
- Copy the following files from the SDK's
Core/directory intopackages/cubism/Core/:live2dcubismcore.jslive2dcubismcore.min.jslive2dcubismcore.d.ts
These files are not included in the repository due to Live2D's license restrictions.
- Repository code:
MPL-2.0 - Live2D Cubism Core and model assets follow their official licenses
