pixi-vn-canvas
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePixi'VN Canvas
Pixi'VN Canvas
The Canvas module is Pixi'VN's 2D scene graph, built directly on top of PixiJS. It manages
everything that is visually rendered in the game: background images, character sprites, text,
video, and the transitions/animations between them. Official docs:
pixi-vn.com/start/canvas.
Every symbol used below (, , , transition helpers, etc.) is exported
from the main package entry point:
canvasshowImageSpritets
import { canvas } from "@drincs/pixi-vn";(Also available from the narrower subpath — see for when to prefer that.)
@drincs/pixi-vn/canvaspixi-vn-getting-startedCanvas 模块是 Pixi'VN 的 2D 场景图,直接构建于 PixiJS 之上。它负责管理游戏中所有以视觉方式呈现的内容:背景图像、角色精灵、文本、视频,以及它们之间的转场/动画。官方文档:
pixi-vn.com/start/canvas。
以下使用的所有符号(、、、转场辅助函数等)均从主包入口导出:
canvasshowImageSpritets
import { canvas } from "@drincs/pixi-vn";也可以从范围更窄的 子路径导入——何时优先使用它,请参阅 。
@drincs/pixi-vn/canvaspixi-vn-getting-startedWhen to use this skill
何时使用此 skill
Load this skill whenever a task involves:
- Showing, replacing, or removing an image/sprite/video/text on screen.
- Building a composite character sprite out of several image layers.
- Applying a transition (dissolve, fade, move, zoom, push, wipe, iris, split, flash, blur, pixelate) when a background or sprite changes.
- Adding a shake effect or a custom PixiJS-ticker-driven animation.
- Reading or modifying canvas element position/anchor/alpha/zIndex.
For building/mounting UI layers (HTML or PixiJS) on top of the canvas, use instead —
this skill is about the save-able scene graph, not UI chrome.
pixi-vn-uigameLayerFor dialogue/character-portrait logic use and instead;
this skill is about the underlying rendering primitives.
pixi-vn-characterspixi-vn-narration只要任务涉及以下内容,就应加载此 skill:
- 在屏幕上显示、替换或移除图像、精灵、视频或文本。
- 使用多个图像层构建复合角色精灵。
- 在背景或精灵发生变化时应用转场(溶解、淡入淡出、移动、缩放、推移、擦除、光圈、分割、闪烁、模糊、像素化)。
- 添加抖动效果或由 PixiJS ticker 驱动的自定义动画。
- 读取或修改 canvas 元素的位置、锚点、透明度或 zIndex。
如需在 Canvas 上构建或挂载 UI 层(HTML 或 PixiJS),请使用 ——此 skill 关注的是可保存的 场景图,而不是 UI 框架。
pixi-vn-uigameLayer如需处理对话或角色立绘逻辑,请使用 和 ;此 skill 关注的是底层渲染原语。
pixi-vn-characterspixi-vn-narrationCore mental model
核心心智模型
- (from
canvas) is the single entry-point object developers use. It wraps a PixiJS@drincs/pixi-vnand exposes methods to manage canvas elements and layers. CallApplicationonce at startup (this is normally done for you byawait canvas.init(element, options)from the core package — seeGame.init(...)).pixi-vn-getting-started - Elements are tracked by alias, not by variable (docs).
inserts a component (an instance of
canvas.add(alias, component),Container,Sprite,ImageSprite,ImageContainer, orText) intoVideoSprite(a single PixiJScanvas.layers.gameLayerthat holds all "in-scene" elements) and setsContainer. Usecomponent.label = aliasto look elements back up andcanvas.find<T>(alias)to remove them. Aliases are also how Pixi'VN saves/restores canvas state (seecanvas.remove(alias)), so prefer the alias-based helpers below over holding onto raw object references across steps.pixi-vn-storage - Every element class is a save-able extension of a PixiJS class: extends
Container,PIXI.Container/Sprite/ImageSpriteextendVideoSprite,PIXI.SpriteextendsText. They add aPIXI.Textgetter /.memoryfor serialization, plus convenience properties (.setMemory(),anchor,align,percentagePosition/xAlign,yAlign/percentageX) as alternative ways to position an element without doing pixel math.percentageY - is just a type alias for a plain
Layer— there's no special Layer class. A separate, non-save-able PixiJS Container can be attached directly to the stage as a sibling ofPIXI.Container<ContainerChild>(gameLayer/canvas.layers.add/get) — seeremovefor that API, it's how UI layers (HTML or PixiJS) are built on top of the canvas.pixi-vn-ui - Tickers are how frame-based animation and effects work under the hood; (built on the
canvas.animate(...)library) is the high-level way to animate numeric properties over time, and it is what all the built-in transition helpers use internally. Running tickers are managed through the separatemotionsingleton (also fromtickers, not a member of@drincs/pixi-vn— the oldcanvasis a deprecated alias of it).canvas.tickers
- (来自
canvas)是开发者使用的单一入口对象。它包装了一个 PixiJS@drincs/pixi-vn,并提供用于管理 canvas 元素和图层的方法。在启动时调用一次Application(通常由核心包中的await canvas.init(element, options)自动完成——请参阅Game.init(...))。pixi-vn-getting-started - 元素通过 alias 跟踪,而不是通过变量跟踪(文档)。会将组件(
canvas.add(alias, component)、Container、Sprite、ImageSprite、ImageContainer或Text的实例)插入VideoSprite(一个包含所有场景内元素的 PixiJScanvas.layers.gameLayer),并将Container设置为 alias。使用component.label查找元素,使用canvas.find<T>(alias)移除元素。Pixi'VN 同样通过 alias 保存和恢复 canvas 状态(请参阅canvas.remove(alias)),因此在多个步骤之间应优先使用以下基于 alias 的辅助方法,而不是持有原始对象引用。pixi-vn-storage - 每个元素类都是某个 PixiJS 类的可保存扩展版本:扩展
Container,PIXI.Container/Sprite/ImageSprite扩展VideoSprite,PIXI.Sprite扩展Text。它们新增了用于序列化的PIXI.Textgetter/.memory,以及一些便捷属性(.setMemory()、anchor、align、percentagePosition/xAlign、yAlign/percentageX),可通过这些属性定位元素,而无须进行像素计算。percentageY - 只是普通
Layer的类型别名——不存在特殊的 Layer 类。可以将一个独立的、不可保存的 PixiJS Container 作为PIXI.Container<ContainerChild>的同级节点直接挂载到 stage(gameLayer/canvas.layers.add/get)——相关 API 请参阅remove,它正是用于在 Canvas 上构建 UI 层的方式。pixi-vn-ui - Ticker 是逐帧动画和效果在底层的工作机制;(基于
canvas.animate(...)库构建)是对数值属性进行随时间动画处理的高级方式,所有内置转场辅助函数在内部都使用它。运行中的 ticker 由独立的motion单例管理(同样来自tickers,并不是@drincs/pixi-vn的成员——旧的canvas是它的弃用别名)。canvas.tickers
Showing and removing an image
显示和移除图像
ts
import { 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");Always pass a manifest alias (as above), not a raw URL/path — see for how
assets get registered (local vs. online) and loaded. / do also accept a raw
URL as a second argument for quick prototyping, but that couples code to a specific file location;
/ throw a if neither a URL nor a registered alias resolves. Both
return an .
pixi-vn-assetsaddImageshowImageaddImageshowImagePixiErrorImageSpriteFor a composite image made of multiple stacked textures (e.g. a character body + outfit + face),
use via / (note the exported spelling
"Cointainer"):
ImageContaineraddImageCointainershowImageContainerts
import { showImageContainer } from "@drincs/pixi-vn";
const liam = await showImageContainer("liam", ["liam-body", "liam-head"]);ts
import { 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");始终传入资源清单中的 alias(如上例),而不是原始 URL/路径——有关如何注册资源(本地或在线)并加载资源,请参阅 。为了快速原型开发,/ 也接受作为第二个参数传入的原始 URL,但这会将代码耦合到特定文件位置;如果 URL 和已注册的 alias 均无法解析,/ 会抛出 。两者都会返回 。
pixi-vn-assetsaddImageshowImageaddImageshowImagePixiErrorImageSprite如需创建由多个堆叠纹理组成的复合图像(例如角色身体、服装和脸部),请使用 ,并通过 / 调用(请注意导出名称的拼写为 ):
ImageContaineraddImageCointainershowImageContainerCointainerts
import { showImageContainer } from "@drincs/pixi-vn";
const liam = await showImageContainer("liam", ["liam-body", "liam-head"]);Adding text
添加文本
ts
import { showText } from "@drincs/pixi-vn";
showText("score-label", "Score: 0", {
fontSize: 24,
fill: "white",
x: 20,
y: 20,
});showText(alias, text, options)TextPIXI.TextoptionsTextOptionsCanvasTextOptionsalignpercentagePositionstylefontSizefillxyts
import { showText } from "@drincs/pixi-vn";
showText("score-label", "Score: 0", {
fontSize: 24,
fill: "white",
x: 20,
y: 20,
});showText(alias, text, options)TextPIXI.TextoptionsTextOptionsCanvasTextOptionsalignpercentagePositionstylefontSizefillxyPlaying a video
播放视频
ts
import { 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.movcheckIfVideots
import { 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.movcheckIfVideoTransitions
转场
All transition helpers take . If you omit the
component/URL argument, the itself is used as the texture URL/alias. Each function
replaces (or removes) whatever is currently registered under , transferring position and
running tickers from the old element automatically. They all return a (or array) of
ticker ids you can pass to if you need to await completion, but
usually you just call and move on.
(alias, componentOrUrl?, props?, priority?)aliasaliasPromisetickers.forceCompletionts
import {
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 });propsAnimationOptionsmotiondurationeasecompleteOnContinuetrue所有转场辅助函数都采用 签名。如果省略组件/URL 参数,则会使用 本身作为纹理 URL/alias。每个函数都会替换或移除当前注册在对应 下的元素,并自动转移其位置和正在运行的 ticker。它们会返回一个 Promise(或 Promise 数组),其中包含可供传递给 的 ticker id;如果需要等待动画完成,可以使用该结果,但通常只需调用后继续执行即可。
(alias, componentOrUrl?, props?, priority?)aliasaliastickers.forceCompletionts
import {
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 });propsmotionAnimationOptionsdurationeasecompleteOnContinuetrueGeneric reveal/filter transitions: wipe, iris, split, flash, blur, pixelate, glitch, twist, warp, ripple, noiseDissolve, tv, pinch
通用显示/滤镜转场:wipe、iris、split、flash、blur、pixelate、glitch、twist、warp、ripple、noiseDissolve、tv、pinch
These are only exposed through the namespace (no flat top-level export like the
older /), each as a matched / pair with the same
/ shapes as above.
They favor a handful of configurable options over narrative-specific variants — e.g. there's one
, not /.
transitionsmoveInshowWithDissolvexInxOut(alias, componentOrUrl?, props?, priority?)(alias, props?, priority?)wipeInwipeLeftwipeRightts
import { 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 });Distortion transitions (glitch, twist, warp, ripple, pinch) move pixels around, so they read best on
images with detail - on a flat, single-color element they're much less visible.
They compose freely since each drives its own mask (//) or filter
(///...) independently — e.g. call and then on the same alias to
combine both. Common narrative effects are just recipes built from these primitives rather than
dedicated functions: a "blink"/eyes-opening effect is a color overlay plus an iris reveal, a
"dream"/flashback is + , a memory transition is a color overlay plus
, a "curtain" is a configured , and a diagonal wipe is just /
with a non-cardinal .
wipeirissplitblurpixelateglitchblurInwipeInblurInshowWithFadeblurInsplitOutwipeInwipeOutangle这些转场仅通过 命名空间公开(不像旧版 / 那样提供扁平的顶层导出),每种转场都有相互对应的 / 形式,其 或 参数结构与上述函数相同。相比面向叙事的专用变体,它们更倾向于提供少量可配置选项——例如只有一个 ,而不是 /。
transitionsmoveInshowWithDissolvexInxOut(alias, componentOrUrl?, props?, priority?)(alias, props?, priority?)wipeInwipeLeftwipeRightts
import { 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 });畸变转场(glitch、twist、warp、ripple、pinch)会移动像素,因此最适合用于包含丰富细节的图像;在纯色的单一元素上,其效果会明显弱得多。
这些转场可以自由组合,因为每种转场都会独立驱动自己的遮罩(//)或滤镜(// 等)——例如,可以对同一个 alias 依次调用 和 ,将两种效果结合起来。常见的叙事效果通常只是由这些原语组合而成的配方,而不是专用函数:例如“眨眼”/睁眼效果由颜色叠加和光圈显示组成,“梦境”/闪回由 和 组成,记忆转场由颜色叠加和 组成,“幕布”效果是配置后的 ,对角擦除则只需使用非正交 调用 /。
wipeirissplitblurpixelateglitchblurInwipeInblurInshowWithFadeblurInsplitOutanglewipeInwipeOutCreating custom transitions
创建自定义转场
A custom transition is just a plain function that adds/replaces a component and drives it with
— the same primitive , , etc. are built on:
canvas.animateshowWithDissolvemoveInts
import { 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];
}If a component under the same alias may already exist, either let replace it
outright (per the heredity-factor gotcha above), or explicitly swap it in first — rename the old
component's alias, add the new one, restore z-order, then transfer its properties/tickers — so an
in-flight animation on the old element carries over instead of snapping:
canvas.addts
let 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");To remove the old component only once the new one's transition finishes, pass
in 's instead of removing it
manually. To have the old component run its own transition-out (instead of a hard cut), give it a
second call paused with and resumed via the new call's
option — see the wiki's own two worked examples for the exact sequencing.
aliasToRemoveAfter: oldComponentAliascanvas.animateoptionscanvas.animatetickers.pause({ id })tickerIdToResumeAnimating a filter's own property instead of a component property — for effects like blur,
pixelate, glow, or color grading, use (from , available
since v1.9.4) instead of . It mirrors the same
shape with the instance inserted as the second
argument; you attach the filter to yourself before animating, and detach +
destroy it in the callback (the 7th argument) once the animation completes — this is
exactly how /// are implemented:
filters.animate@drincs/pixi-vn/filterscanvas.animate(alias, keyframes, options, priority)Filtercomponent.filterscleanuptransitions.blurInblurOutpixelateInpixelateOutts
import { 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.animateundefinedapplywipeInirisInsplitIn自定义转场只是一个普通函数,用于添加或替换组件,并通过 驱动组件——、 等内置转场也是基于这一原语构建的:
canvas.animateshowWithDissolvemoveInts
import { 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];
}如果同一 alias 下可能已经存在组件,可以直接让 替换它(遵循上述 heredity-factor 注意事项),也可以先显式交换组件——重命名旧组件的 alias,添加新组件,恢复 z-order,然后转移其属性/ticker——这样旧元素上正在进行的动画便能延续,而不会突然跳变:
canvas.addts
let 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");如果只应在新组件的转场完成后移除旧组件,请在 的 中传入 ,而不要手动移除。如果希望旧组件运行自己的转场退出效果(而不是直接切换),可以再发起一次 调用,先使用 将其暂停,再通过新调用的 选项恢复——准确的执行顺序请参阅 wiki 中的两个完整示例。
canvas.animateoptionsaliasToRemoveAfter: oldComponentAliascanvas.animatetickers.pause({ id })tickerIdToResume不对组件属性、而是对滤镜自身的属性进行动画处理——对于模糊、像素化、辉光或色彩分级等效果,应使用 (来自 ,自 v1.9.4 起提供),而不是 。它具有相同的 参数结构,第二个参数为 实例;你需要在动画前自行将滤镜附加到 ,并在动画完成后的 回调(第 7 个参数)中分离和销毁滤镜——/// 正是这样实现的:
filters.animate@drincs/pixi-vn/filterscanvas.animate(alias, keyframes, options, priority)Filtercomponent.filterscleanuptransitions.blurInblurOutpixelateInpixelateOutts
import { 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.animateundefinedapplywipeInirisInsplitInShake and other articulated animations
抖动及其他 articulated animations
The namespace holds "articulated animations" — helpers built on top of
that bake a full keyframe array once and animate it in a single call (docs:
canvas-articulated-animations-effects,
canvas-motion). Like the transitions above, these are
generic primitives — the effect describes how a component moves, the game decides what that
means (a hit reaction, an idle fidget, an emphasis beat, ...).
effectscanvas.animatets
import { 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 });There's no separate "tremble"/"vibration" primitive — that's just configured with a
small and a high (high-frequency, low-amplitude shaking).
shakeEffectmaxShockSizeshocksNumbereffectscanvas.animatets
import { 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 });系统没有单独的“颤抖”/“振动”原语——只需将 配置为较小的 和较高的 ,即可实现高频、低振幅的抖动。
shakeEffectmaxShockSizeshocksNumberFilter-based articulated animations
基于滤镜的 articulated animations
The same namespace also has primitives built on the module (raw /
filter classes, re-exported as - see ) instead of
: each one attaches a filter to the component, drives one of the filter's own
properties through a decaying (or one-shot) keyframe array via , and detaches/destroys
the filter once done - the component is left exactly as it was before, same guarantee as every effect
above.
effectsfilterspixi-filterspixi.jsfilters.*@drincs/pixi-vn/filterscanvas.animatefilters.animatets
import { 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 });All 8 are per-component (same pattern as everything else here) - there's no screen-wide/global
filter effect yet. Distortion effects (glitch, chromatic aberration, shockwave, radial blur) move
pixels around, so they only read on an image with detail/edges - on a flat, single-color element they
look like nothing happened. Build a custom one the same way: construct any class, attach it to
yourself, and drive it with (see the low-level example just above
this section) - / (color grading), /
(retro looks), and / (glow) are good starting points not covered above.
aliasfilters.*component.filtersfilters.animateAdjustmentFilterHslAdjustmentFilterCRTFilterOldFilmFilterBloomFilterAdvancedBloomFiltercanvas.animate(componentOrAlias, keyframes, options, priority)animateoptionsdurationeaserepeatcanvas.animaterequestAnimationFrameanimate@drincs/pixi-vn/motion同一个 命名空间还提供了一组基于 模块构建的原语,而不是使用 。这些原语使用原始的 / 滤镜类(通过 重新导出——请参阅 ):每种效果都会将滤镜附加到组件,通过 使用衰减式或一次性关键帧数组驱动滤镜自身的属性,并在完成后分离和销毁滤镜——组件最终会恢复到执行前的状态,与上述所有效果具有相同的保证。
effectsfilterscanvas.animatepixi-filterspixi.jsfilters.*@drincs/pixi-vn/filtersfilters.animatets
import { 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 });这 8 种效果均按组件生效(使用与此处其他功能相同的 模式)——目前尚不支持全屏或全局滤镜效果。畸变效果(glitch、chromatic aberration、shockwave、radial blur)会移动像素,因此只有在包含细节或边缘的图像上才会清晰可见;在纯色的单一元素上,看起来会像什么都没发生。可以用相同方式构建自定义效果:创建任意 类,自行将其附加到 ,再使用 驱动它(请参阅上一节的低层级示例)。/(色彩分级)、/(复古效果)和 /(辉光)都是不错的起点,但未包含在上述效果中。
aliasfilters.*component.filtersfilters.animateAdjustmentFilterHslAdjustmentFilterCRTFilterOldFilmFilterBloomFilterAdvancedBloomFiltercanvas.animate(componentOrAlias, keyframes, options, priority)motionanimateoptionsdurationeaserepeatcanvas.animaterequestAnimationFrame@drincs/pixi-vn/motionanimateFrame tickers
帧 Ticker
canvas.animatetickers.mdTickertickers.addSequencetickers.pauseresumeremovetickers.completeOnStepEndcanvas.animatetickers.mdTickertickers.addSequencetickers.pauseresumeremovetickers.completeOnStepEndExternal rendering plugins
外部渲染插件
These optional packages are installed separately from ; their component
classes must be imported from the plugin, not the engine. Check the installed package's peer
dependencies and types before adapting examples to a project's PixiJS/Pixi'VN versions.
@drincs/pixi-vn以下可选包需要与 分开安装;它们的组件类必须从插件中导入,而不能从引擎中导入。在调整示例以适配项目的 PixiJS/Pixi'VN 版本之前,请检查已安装包的 peer dependencies 和类型定义。
@drincs/pixi-vnLive2D: @drincs/pixi-vn-live2d
@drincs/pixi-vn-live2dLive2D:@drincs/pixi-vn-live2d
@drincs/pixi-vn-live2dUse this wrapper around for Live2D models. Register its render
plugin before (or ):
untitled-pixi-live2d-engineGame.init()canvas.init()ts
import { extensions } from "pixi.js";
import { Live2DPlugin } from "@drincs/pixi-vn-live2d/core";
extensions.add(Live2DPlugin);
// Initialize the game/canvas after registering the plugin.Once the canvas is initialized, register the model asset and await model readiness before
controlling it:
ts
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);Consult the plugin README for setup
and its API reference
for model options. Do not substitute for .
ImageSprite.load()Live2D.ready使用这个基于 的包装器来渲染 Live2D 模型。必须在 (或 )之前注册渲染插件:
untitled-pixi-live2d-engineGame.init()canvas.init()ts
import { extensions } from "pixi.js";
import { Live2DPlugin } from "@drincs/pixi-vn-live2d/core";
extensions.add(Live2DPlugin);
// Initialize the game/canvas after registering the plugin.Canvas 初始化后,应注册模型资源,并在控制模型前等待模型就绪:
ts
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);Spine: @drincs/pixi-vn-spine
@drincs/pixi-vn-spineSpine:@drincs/pixi-vn-spine
@drincs/pixi-vn-spineUse this wrapper around for skeletal animation. Add
to the app entry point: importing the package registers
the serializable component. A lazy scene import alone is insufficient when a save is restored
before that scene has ever loaded.
@esotericsoftware/spine-pixi-v8import "@drincs/pixi-vn-spine";Register the skeleton and atlas in the asset manifest, then load both before construction:
ts
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);See the Spine guide for skins and tracks and the
package README for save-registration
details. Keep the Pixi'VN wrapper when adding saved scene elements.
使用这个基于 的包装器进行骨骼动画。将 添加到应用入口点:导入该包会注册可序列化组件。如果在某个场景从未加载过之前恢复了存档,仅在场景中执行延迟导入并不足以完成注册。
@esotericsoftware/spine-pixi-v8import "@drincs/pixi-vn-spine";在资源清单中注册骨架和图集,然后在构建前加载二者:
ts
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);UI layers
UI 层
Persistent UI chrome (HUD, menus) does not live on — it lives on a separate,
non-save-able layer built with // (PixiJS-only UI) or
// (mounting a DOM-based UI framework like React
or Vue). That whole API, plus the official template's layer-naming conventions, for
save-file thumbnails, and how to build a UI purely out of PixiJS components, is covered by
— reach for that skill instead whenever the task is about UI rather than the game scene.
gameLayercanvas.layers.addgetremovecanvas.htmlLayers.addgetremoveextractImage()pixi-vn-ui持久化 UI 框架(HUD、菜单)不位于 中——它位于一个独立的、不可保存的层中,可通过 // 构建纯 PixiJS UI,或通过 // 挂载基于 DOM 的 UI 框架(如 React 或 Vue)。整个 API、官方模板的图层命名约定、用于生成存档缩略图的 ,以及如何完全使用 PixiJS 组件构建 UI,均由 覆盖——只要任务与 UI 而非游戏场景有关,就应使用该 skill。
gameLayercanvas.layers.addgetremovecanvas.htmlLayers.addgetremoveextractImage()pixi-vn-uiGotchas
注意事项
- /
addImage/addVideoonly construct and register the element — the texture is not loaded/visible until youaddImageCointainer. Theawait element.load()variants (show*,showImage,showVideo, and the transition helpers) callshowImageContainerfor you; prefer them unless you need to prepare an element off-screen first.load() - /
getTexturethrow aload()(PixiError) if the alias can't be resolved from the PixiJSunregistered_assetcache/manifest. SeeAssetsfor how to register an alias (local assets via AssetPack, or online assets inpixi-vn-assets) before referencing it here.src/assets/index.ts - Adding an element with an alias that already exists replaces it and — per the
"heredity factor" — copies over
properties//tickers from the old one by default (
zIndexto opt out) — this is what letscanvas.add(alias, el, { ignoreOldStyle: true })"just work" as a same-alias swap.showImage("bg", newUrl) - also removes tickers bound only to that alias; pass
canvas.remove(alias)if you intend to reattach them elsewhere first.{ ignoreTickers: true } - Event listeners use plain PixiJS , not a Pixi'VN-specific method — a stray JSDoc comment in the
.on(...)source suggestsSprite, but that method doesn't exist; the official docs confirmsprite.onEvent(...)is correct. The Pixi'VN-specific part is only the.on(...)requirement for save/load:@eventDecorator()only serializes correctly ifsprite.on("pointerdown", Events.handler)is a static method decorated withEvents.handler(from@eventDecorator()); a plain inline arrow function will log a warning and not be restored after loading a save.@drincs/pixi-vn - Positioning has multiple parallel systems (docs: canvas-position)
— pixel (/
x/y), anchor/position(where on the element itself the position point sits),pivot/align/xAlign(Ren'Py-style percentage-of-canvas positioning, e.g.yAlign= centered; per source JSDoc,0.5does not affectpivot), andalign/percentagePosition/percentageX(also percentage-of-parent, butpercentageYdoes affect it, unlikepivot). Settingalign/x/alignon the same axis clears the others; checkpercentagePosition/element.positionTypeif you need to know which mode is active.element.positionInfo - (
CANVAS_APP_GAME_LAYER_ALIAS) is reserved —"__game_layer__",canvas.add, andremovewill refuse to use that alias.addLayer - /
canvas.pause()stop/restart rendering and tickers for the whole game layer (e.g. when opening a menu) — remember to callcanvas.resume()or elements will appear frozen.resume()
- /
addImage/addVideo只负责创建和注册元素——在调用addImageCointainer之前,纹理尚未加载或显示。await element.load()变体(show*、showImage、showVideo及转场辅助函数)会替你调用showImageContainer;除非需要先在屏幕外准备元素,否则应优先使用它们。load() - 如果 alias 无法从 PixiJS 缓存或清单中解析,
Assets/getTexture会抛出load()(PixiError)。 请参阅unregistered_asset,了解如何在使用 alias 前注册它(通过 AssetPack 注册本地资源,或在pixi-vn-assets中注册在线资源)。src/assets/index.ts - 添加一个已存在 alias 的元素会替换原元素,并且根据“heredity factor”,默认会从旧元素复制属性、和 ticker(可通过
zIndex退出此行为)——正是这一机制让canvas.add(alias, el, { ignoreOldStyle: true })能够直接完成同 alias 的内容替换。showImage("bg", newUrl) - 也会移除仅绑定到该 alias 的 ticker;如果打算先将它们重新附加到其他位置,请传入
canvas.remove(alias)。{ ignoreTickers: true } - 事件监听器使用原生 PixiJS 的 ,而不是 Pixi'VN 专用方法——
.on(...)源码中某个 JSDoc 注释提示应使用Sprite,但该方法并不存在;官方文档确认应使用sprite.onEvent(...)。Pixi'VN 特有要求仅涉及保存/加载时必须使用.on(...):只有当@eventDecorator()是使用Events.handler(来自@eventDecorator())装饰的静态方法时,@drincs/pixi-vn才能被正确序列化;普通的内联箭头函数会产生警告,并且在加载存档后无法恢复。sprite.on("pointerdown", Events.handler) - 定位系统有多个并行体系(文档:canvas-position)——像素定位(/
x/y)、锚点/枢轴定位(position/anchor,表示元素自身上的哪个位置与定位点对应)、pivot/align/xAlign(类似 Ren'Py 的按 Canvas 百分比定位,例如yAlign表示居中;根据源码 JSDoc,0.5不影响pivot),以及align/percentagePosition/percentageX(同样按父元素百分比定位,但与percentageY不同,align会影响它)。在同一个轴上设置pivot/x/align会清除其他定位方式;如果需要确定当前生效的模式,请检查percentagePosition/element.positionType。element.positionInfo - (
CANVAS_APP_GAME_LAYER_ALIAS)为保留值——"__game_layer__"、canvas.add和remove会拒绝使用该 alias。addLayer - /
canvas.pause()会停止或重新启动整个游戏层的渲染和 ticker(例如打开菜单时)——记得调用canvas.resume(),否则元素会看起来像是被冻结了。resume()
Related skills
相关 skill
- pixi-vn-getting-started: project setup, , and how the canvas is wired up at startup.
Game.init() - pixi-vn-assets: registering images/video (local or online) and choosing when their bundle loads, before referencing them here by alias.
- pixi-vn-characters: character/emotion definitions that use canvas images under the hood for portraits.
- pixi-vn-narration: dialogue/step flow, and how canvas transitions integrate with .
completeOnContinue - pixi-vn-storage: how canvas element state (by alias) is saved and restored across game saves.
- pixi-vn-ui: building/mounting UI layers (HTML or PixiJS) on top of the canvas — ,
addLayer, and building UI screens with PixiJS components.addHtmlLayer
- pixi-vn-getting-started:项目设置、,以及 Canvas 在启动时如何完成连接。
Game.init() - pixi-vn-assets:在通过 alias 引用图像或视频前,注册本地或在线资源,以及选择资源包的加载时机。
- pixi-vn-characters:角色和情绪定义,其底层会使用 Canvas 图像呈现角色立绘。
- pixi-vn-narration:对话和步骤流程,以及 Canvas 转场如何与 集成。
completeOnContinue - pixi-vn-storage:如何跨游戏存档保存和恢复 Canvas 元素状态(按 alias 管理)。
- pixi-vn-ui:在 Canvas 上构建或挂载 UI 层(HTML 或 PixiJS)——、
addLayer,以及使用 PixiJS 组件构建 UI 屏幕。addHtmlLayer