0.4.0 • Published 5 months ago

pixi-live2d-display v0.4.0

Weekly downloads
29
License
MIT
Repository
github
Last release
5 months ago

pixi-live2d-display

GitHub package.json version Cubism version Codacy Badge

Live2D integration for PixiJS v5.

Only compatible with Cubism 2.1. Support of Cubism 4 is on the way!

Documentation

Play with demo

Install

npm install pixi-live2d-display

This library relies on Promise, you may need a polyfill, e.g. es6-promise.

You'll also need to include the Cubism 2.1 runtime library, which is typically named live2d.min.js. The official download has been gone since 9/4/2019, but its spirit still exists somewhere on the net...

Usage

Basic

import * as PIXI from 'pixi.js';
window.PIXI = PIXI;
import { Live2DModel } from 'pixi-live2d-display';

async function main() {
    const model = await Live2DModel.fromModelSettingsFile('my-model.model.json');

    const app = new PIXI.Application({ autoStart: true });
    app.stage.addChild(model);

    // transformation
    model.position.set(100, 100);
    model.scale.set(2, 2);
    model.anchor.set(0.5, 0.5);

    // motion
    model.on('hit', hitAreas => {
        if(hitAreas.includes('body')) {
            model.motion('tapBody');
        }
    });
}

Modules

It's possible to import only the necessary modules rather than a full build of PixiJS.

import { Application } from '@pixi/app';
import { Live2DModel } from 'pixi-live2d-display';

async function main() {
    const model = await Live2DModel.fromModelSettingsFile('my-model.model.json');

    const app = new Application();
    app.stage.addChild(model);
}

Prebuilt Files

When including prebuilt files by script tag, all exported members are available in PIXI.live2d namespace. For example import { Live2DModel } from 'pixi-live2d-display' becomes PIXI.live2d.Live2DModel.

<script src="pixi.min.js"></script>
<script src="pixi-live2d-display.browser.js"></script>
const app = new PIXI.Application({ autoStart: true });

PIXI.live2d.Live2DModel.fromModelSettingsFile('my-model.model.json').then(model => {
    app.stage.addChild(model);
})

Updating

To make a Live2D model "live", it should be updated with delta time, which is the time elapsed from last frame to this frame, in milliseconds.

When a full build of PixiJS is imported, each model will be automatically updated using window.PIXI.Ticker.shared.

import * as PIXI from 'pixi.js';
window.PIXI = PIXI;

Otherwise you need to register the Ticker to Live2DModel.

import { Application } from '@pixi/app';
import { Ticker, TickerPlugin } from '@pixi/ticker';

Application.registerPlugin(TickerPlugin);
Live2DModel.registerTicker(Ticker);

Or you may want to do it yourself:

import { Ticker } from '@pixi/ticker';

const model = await Live2DModel.fromModelSettingsFile('my-model.model.json', { autoUpdate: false });

new Ticker().add(()=> model.update(Ticker.shared.elapsedMS));

Or without Ticker:

const model = await Live2DModel.fromModelSettingsFile('my-model.model.json', { autoUpdate: false });

let then = performance.now();

function tick(now) {
    model.update(now - then);
    then = now;

    requestAnimationFrame(tick)
}

requestAnimationFrame(tick)

Interaction

Interaction will be automatically set up for each model if Renderer has an InteractionManager plugin, which happens when a full build of PixiJS is imported:

import * as PIXI from 'pixi.js';
window.PIXI = PIXI;

Or when the plugin is manually registered using modules:

import { Renderer } from '@pixi/core';
import { InteractionManager } from '@pixi/interaction';

Renderer.registerPlugin('interaction', InteractionManager);

If you don't want the default behaviour, you can disable it by setting autoInteract to false, then play with corresponding interaction methods.

const model = await Live2DModel.fromModelSettingsFile('my-model.model.json', { autoInteract: false });

// focusing
canvasElement.addEventListener('mousemove', event => model.focus(event.clientX, event.clientY));

// tapping
canvasElement.addEventListener('mousedown', event => model.tap(event.clientX, event.clientY));

When any hit area (also called Collision Detection) is hit on tapping, a hit event will be emitted with an array of the names of hit hit areas.

model.on('hit', hitAreas => {
    if(hitAreas.includes('body')) {
        console.log('hit body')
    }
});

Motion

Motions are managed by MotionManager of each model.

import { Priority } from 'pixi-live2d-display';

// start a random motion in "tap_body" group, note that it's camelCased into "tapBody" when using in the code
model.internal.motionManager.startRandomMotion('tapBody');

// start an explicit motion as normal priority
model.internal.motionManager.startMotionByPriority('tapBody', 0, Priority.Normal);

// a shorthand of startRandomMotion()
model.motion('tapBody');

When a motion starts, the sound will be played (if there is), and a motion event will be emitted.

model.on('motion', (group, index, audio) => {
    if(audio) {
        audio.addEventListener('ended', () => console.log('finished'));    
    }
});

Expression

Expressions are managed by ExpressionManager in MotionManager.

model.internal.motionManager.expressionManager.setRandomExpression();

Sound

Sounds are managed by static SoundManager.

import { SoundManager } from 'pixi-live2d-display';

SoundManager.volume = 0.5;

Global Config

import { config } from 'pixi-live2d-display';

// log level
config.logLevel = config.LOG_LEVEL_WARNING;

// play sound for motions
config.sound = true;

// defer motion and corresponding sound until both are loaded 
config.motionSync = true;

The testing Live2D model, Shizuku, is redistributed under Live2D's Free Material License.