Loading...
Loading...
Use when adding, moving, or removing images, sprites, text, or video on the Pixi'VN game canvas, or when applying or creating transitions (dissolve, fade, move, zoom, push, wipe, iris, split, flash, blur, pixelate, or a custom one built on `canvas.animate`/`filters.animate`), shake/animation effects, or ticker-based animations built on PixiJS. Covers the `canvas` singleton exported from `@drincs/pixi-vn`. For UI layers (HTML or PixiJS) mounted on top of the canvas, see `pixi-vn-ui` instead.
npx skill4agent add drincs-productions/pixi-vn pixi-vn-canvascanvasshowImageSpriteimport { canvas } from "@drincs/pixi-vn";@drincs/pixi-vn/canvaspixi-vn-getting-startedpixi-vn-uigameLayerpixi-vn-characterspixi-vn-narrationcanvas@drincs/pixi-vnApplicationawait canvas.init(element, options)Game.init(...)pixi-vn-getting-startedcanvas.add(alias, component)ContainerSpriteImageSpriteImageContainerTextVideoSpritecanvas.layers.gameLayerContainercomponent.label = aliascanvas.find<T>(alias)canvas.remove(alias)pixi-vn-storageContainerPIXI.ContainerSpriteImageSpriteVideoSpritePIXI.SpriteTextPIXI.Text.memory.setMemory()anchoralignpercentagePositionxAlignyAlignpercentageXpercentageYLayerPIXI.Container<ContainerChild>gameLayercanvas.layers.addgetremovepixi-vn-uicanvas.animate(...)motiontickers@drincs/pixi-vncanvascanvas.tickersimport { canvas, addImage, showImage } from "@drincs/pixi-vn";
// addImage() creates + registers the sprite but does NOT load/display the texture yet
const bunny1 = addImage("bunny1"); // "bunny1" is an alias registered in the assets manifest
await bunny1.load();
// showImage() is addImage() + load() in one call
const bunny2 = await showImage("bunny2");
bunny2.anchor = 0.5;
bunny2.x = canvas.width / 2;
bunny2.y = canvas.height / 2;
// remove it later by alias
canvas.remove("bunny1");pixi-vn-assetsaddImageshowImageaddImageshowImagePixiErrorImageSpriteImageContaineraddImageCointainershowImageContainerimport { showImageContainer } from "@drincs/pixi-vn";
const liam = await showImageContainer("liam", ["liam-body", "liam-head"]);import { showText } from "@drincs/pixi-vn";
showText("score-label", "Score: 0", {
fontSize: 24,
fill: "white",
x: 20,
y: 20,
});showText(alias, text, options)TextPIXI.TextoptionsTextOptionsCanvasTextOptionsalignpercentagePositionstylefontSizefillxyimport { showVideo } from "@drincs/pixi-vn";
const film = await showVideo("intro-film"); // "intro-film" resolves via the assets manifest
film.loop = true;
// film.pause(), film.play(), film.restart(), film.currentTime = 2addVideoshowVideoaddImageshowImageVideoSpriteImageSprite.mp4.webm.movcheckIfVideo(alias, componentOrUrl?, props?, priority?)aliasaliasPromisetickers.forceCompletionimport {
showWithDissolve,
removeWithDissolve, // fade the new image in / fade the current one out
showWithFade,
removeWithFade, // cross-fade old -> new (falls back to dissolve if none exists)
moveIn,
moveOut, // slide in/out from a screen edge
zoomIn,
zoomOut, // scale in/out from a screen edge
pushIn,
pushOut, // new image pushes the old one off-screen
} from "@drincs/pixi-vn";
// change background with a 1s dissolve ("bg-forest" is a manifest alias)
await showWithDissolve("background", "bg-forest", { duration: 1 });
// slide a character sprite in from the left
await moveIn("liam", "liam-neutral", { direction: "left", duration: 0.5 });
// remove a character with a zoom-out toward the right edge
zoomOut("liam", { direction: "right", duration: 0.5 });propsAnimationOptionsmotiondurationeasecompleteOnContinuetruetransitionsmoveInshowWithDissolvexInxOut(alias, componentOrUrl?, props?, priority?)(alias, props?, priority?)wipeInwipeLeftwipeRightimport { transitions } from "@drincs/pixi-vn";
// wipe: a moving boundary reveals/conceals the image. `angle` in degrees (0 = left-to-right, 90 =
// bottom-to-top, ...); `direction` ("up"/"down"/"left"/"right") is a shorthand for the 4 cardinal angles.
await transitions.wipeIn("background", "bg-forest", { direction: "left", duration: 1 });
await transitions.wipeIn("background", "bg-night", { angle: 45, duration: 1 }); // diagonal wipe
transitions.wipeOut("background", { angle: 180, invert: true, duration: 1 });
// iris: an expanding/contracting radial mask. `origin` is normalized (0-1) to the element's own bounds.
await transitions.irisIn("liam", "liam-happy", { origin: { x: 0.5, y: 0.3 }, duration: 0.8 });
transitions.irisOut("liam", { aspect: 2, duration: 0.8 }); // aspect > 1 = wide ellipse instead of a circle
// split: two mask panels move apart/together - covers "curtain" effects without a dedicated API.
await transitions.splitIn("background", "bg-forest", { orientation: "horizontal", duration: 1 });
transitions.splitOut("background", { orientation: "vertical", origin: 0.3, duration: 1 });
// flash: a configurable color overlay (not just white) fades in/hold/out, optionally pulsing.
await transitions.flashIn("background", "bg-forest", { duration: 0.15 }); // white camera-flash reveal
transitions.flashOut("liam", { color: 0xff0033, holdDuration: 0.05, pulses: 3, duration: 0.1 }); // red damage flash
// blur / pixelate: the image is shown already blurred/pixelated and resolves into focus (or the reverse for *Out).
await transitions.blurIn("liam", "liam-happy", { strength: 40, duration: 1 });
transitions.blurOut("liam", { duration: 1 });
await transitions.pixelateIn("background", "bg-forest", { pixelSize: 48, duration: 1 });
transitions.pixelateOut("background", { duration: 1 });
// glitch: jittery slices + red/blue split, settling on *In, building up on *Out.
await transitions.glitchIn("liam", "liam-happy", { strength: 40, bursts: 3 });
// twist: unwinds out of (or winds into) a swirl - `angle` in degrees, `origin` normalized.
transitions.twistOut("liam", { angle: 540 });
// warp: radial zoom-blur streaks, like dropping out of / jumping into hyperspace.
await transitions.warpIn("background", "bg-space", { strength: 0.6 });
// ripple: fades in/out through a spreading water ring - dreams, magic, memories.
await transitions.rippleIn("liam", "liam-dream", { origin: { x: 0.5, y: 0.3 } });
// noiseDissolve: the classic VN image dissolve - organic noise blotches (`edge: "soft"` for a cloudy fade).
await transitions.noiseDissolveIn("background", "bg-night", { edge: "hard", noiseScale: 8 });
// tv: old TV switching on (dot -> glowing line -> image) / off; scales around the anchor (center it).
transitions.tvOut("liam", { lineThickness: 0.02, brightness: 3 });
// pinch: emerges from / is sucked into a point (`mode: "bulge"` puffs out instead).
transitions.pinchOut("liam", { mode: "pinch" });
// move/push also take an optional motion-blur trail (true = 40px, or a length in pixels).
await transitions.moveIn("liam", "liam-happy", { direction: "right", duration: 0.6, motionBlur: true });wipeirissplitblurpixelateglitchblurInwipeInblurInshowWithFadeblurInsplitOutwipeInwipeOutanglecanvas.animateshowWithDissolvemoveInimport { canvas, ImageSprite, UPDATE_PRIORITY } from "@drincs/pixi-vn";
import { AnimationOptions } from "@drincs/pixi-vn/motion";
export default async function showWithDissolve(
alias: string,
component: ImageSprite,
props: AnimationOptions = {},
priority?: UPDATE_PRIORITY,
): Promise<string[] | undefined> {
const { completeOnContinue = true, ...options } = props;
canvas.add(alias, component);
component.alpha = 0;
const id = canvas.animate(alias, { alpha: 1 }, { ...options, completeOnContinue }, priority);
if (component.haveEmptyTexture) await component.load();
if (id) return [id];
}canvas.addlet oldComponentAlias: string | undefined;
const oldComponent = canvas.find(alias);
if (oldComponent) {
oldComponentAlias = `${alias}_temp`;
canvas.editAlias(alias, oldComponentAlias);
}
canvas.add(alias, component);
oldComponent?.parent?.setChildIndex(oldComponent, oldComponent.parent.getChildIndex(oldComponent) - 0.1);
oldComponentAlias && canvas.copyCanvasElementProperty(oldComponentAlias, alias);
oldComponentAlias && tickers.transfer(oldComponentAlias, alias, "duplicate");aliasToRemoveAfter: oldComponentAliascanvas.animateoptionscanvas.animatetickers.pause({ id })tickerIdToResumefilters.animate@drincs/pixi-vn/filterscanvas.animate(alias, keyframes, options, priority)Filtercomponent.filterscleanuptransitions.blurInblurOutpixelateInpixelateOutimport { canvas, ImageSprite, UPDATE_PRIORITY } from "@drincs/pixi-vn";
import { filters } from "@drincs/pixi-vn/filters";
import { AnimationOptions } from "@drincs/pixi-vn/motion";
export default async function blurIn(
alias: string,
component: ImageSprite,
props: AnimationOptions & { strength?: number } = {},
priority?: UPDATE_PRIORITY,
): Promise<string[] | undefined> {
const { strength = 32, completeOnContinue = true, ...options } = props;
canvas.add(alias, component);
const filter = new filters.BlurFilter({ strength });
component.filters = [filter];
const id = filters.animate(
alias,
filter,
{ strength: [strength, 0] },
{ ...options, completeOnContinue },
priority,
undefined, // apply - only needed when filter is undefined (see below)
() => {
component.filters = null;
filter.destroy();
},
);
if (component.haveEmptyTexture) await component.load();
if (id) return [id];
}filters.animateundefinedapplywipeInirisInsplitIneffectscanvas.animateimport { effects, canvas } from "@drincs/pixi-vn";
// shake a canvas element horizontally
await effects.shakeEffect("screen-flash-target", {
shakeType: "horizontal",
maxShockSize: 15,
shocksNumber: 10,
});
// bounce: one-directional decaying displacement, e.g. a character landing a jump
await effects.bounceEffect("liam", { direction: "up", distance: 30, bounces: 3 });
// pulse: decaying scale bump, e.g. emphasizing a UI element or a heartbeat
await effects.pulseEffect("liam", { scale: 1.3, pulses: 2 });
// hop: a single displacement-and-return, optionally with smaller decaying follow-up hops
await effects.hopEffect("liam", { direction: "up", distance: 40, secondaryHops: 2 });
// wiggle: decaying rotation oscillation, e.g. a "no" head-shake or a nervous tic
await effects.wiggleEffect("liam", { angle: 15, repetitions: 3 });
// nod: decaying positional oscillation along one axis, e.g. a "yes" nod or a flinch
await effects.nodEffect("liam", { axis: "vertical", distance: 10, repetitions: 3 });
// sway: smooth combined position+rotation drift, e.g. an idle breathing/swaying loop
// (decay defaults to 0 = constant amplitude, unlike the other primitives above)
await effects.swayEffect("liam", { distance: 8, angle: 3, repetitions: 4 });
// punch: a single fast impulse with a settle-back overshoot, e.g. taking a hit
await effects.punchEffect("liam", { mode: "scale", strength: 0.3, overshoot: 0.3 });
await effects.punchEffect("liam", { mode: "rotation", strength: 20 });
// low-level: animate arbitrary numeric properties with motion-style keyframes
canvas.animate("liam", { alpha: [0, 1], y: [50, 0] }, { duration: 0.8 });shakeEffectmaxShockSizeshocksNumbereffectsfilterspixi-filterspixi.jsfilters.*@drincs/pixi-vn/filterscanvas.animatefilters.animateimport { effects } from "@drincs/pixi-vn";
// glitch: jittery, decaying bursts of slice displacement with a matching red/blue channel split
// (returns two ticker ids; `rgbSplit: 0` drops the channel split)
await effects.glitchEffect("liam", { strength: 40, bursts: 3, rgbSplit: 6 });
// chromaticAberration: red/blue channels split apart and snap back, in a decaying burst
await effects.chromaticAberrationEffect("liam", { strength: 8, axis: "horizontal" });
// shockwave: a single ripple distortion travels outward from `origin` (normalized to the element's
// bounds) - by default until it has fully left the element
await effects.shockwaveEffect("liam", { origin: { x: 0.5, y: 0.5 } });
// radialBlur: a decaying burst of zoom-blur radiating from `origin` (normalized to the element's bounds)
await effects.radialBlurEffect("liam", { strength: 0.3, bursts: 1 });
// blurPulse: a repeated, decaying blur bump (distinct from blurIn/blurOut, which are one-shot
// reveal/conceal transitions, not a repeated pulse)
await effects.blurPulseEffect("liam", { strength: 8, pulses: 3 });
// vignettePulse: the edges darken and recover, in a repeated, decaying pulse - it darkens the corners
// of the element's own rectangle, so use it on backgrounds/full-frame images, not on characters
await effects.vignettePulseEffect("background", { strength: 1, pulses: 1, radius: 0.5 });
// desaturate: color drains out and recovers - a single dip, not a repeated pulse
await effects.desaturateEffect("liam", { amount: 0, holdDuration: 0.2 });
// glowPulse: a repeated, decaying outward glow
await effects.glowPulseEffect("liam", { strength: 4, pulses: 3, color: 0xffee00 });aliasfilters.*component.filtersfilters.animateAdjustmentFilterHslAdjustmentFilterCRTFilterOldFilmFilterBloomFilterAdvancedBloomFiltercanvas.animate(componentOrAlias, keyframes, options, priority)animateoptionsdurationeaserepeatcanvas.animaterequestAnimationFrameanimate@drincs/pixi-vn/motioncanvas.animatetickers.mdTickertickers.addSequencetickers.pauseresumeremovetickers.completeOnStepEnd@drincs/pixi-vn@drincs/pixi-vn-live2duntitled-pixi-live2d-engineGame.init()canvas.init()import { extensions } from "pixi.js";
import { Live2DPlugin } from "@drincs/pixi-vn-live2d/core";
extensions.add(Live2DPlugin);
// Initialize the game/canvas after registering the plugin.import { Assets, canvas } from "@drincs/pixi-vn";
import { Live2D } from "@drincs/pixi-vn-live2d";
Assets.add({ alias: "hero-model", src: "/models/hero/model3.json" });
const model = new Live2D({ source: "hero-model" });
await model.ready;
model.motion("Idle"); // Use a motion group present in this model.
canvas.add("hero", model);ImageSprite.load()Live2D.ready@drincs/pixi-vn-spine@esotericsoftware/spine-pixi-v8import "@drincs/pixi-vn-spine";import { Assets, canvas } from "@drincs/pixi-vn";
import { Spine } from "@drincs/pixi-vn-spine";
await Assets.load(["hero-skeleton", "hero-atlas"]);
const model = new Spine({ skeleton: "hero-skeleton", atlas: "hero-atlas" });
model.setAnimation(0, "idle", true); // Animation names come from the skeleton.
canvas.add("hero", model);gameLayercanvas.layers.addgetremovecanvas.htmlLayers.addgetremoveextractImage()pixi-vn-uiaddImageaddVideoaddImageCointainerawait element.load()show*showImageshowVideoshowImageContainerload()getTextureload()PixiErrorunregistered_assetAssetspixi-vn-assetssrc/assets/index.tszIndexcanvas.add(alias, el, { ignoreOldStyle: true })showImage("bg", newUrl)canvas.remove(alias){ ignoreTickers: true }.on(...)Spritesprite.onEvent(...).on(...)@eventDecorator()sprite.on("pointerdown", Events.handler)Events.handler@eventDecorator()@drincs/pixi-vnxypositionpivotalignxAlignyAlign0.5pivotalignpercentagePositionpercentageXpercentageYpivotalignxalignpercentagePositionelement.positionTypeelement.positionInfoCANVAS_APP_GAME_LAYER_ALIAS"__game_layer__"canvas.addremoveaddLayercanvas.pause()canvas.resume()resume()Game.init()completeOnContinueaddLayeraddHtmlLayer