Game Asset Generator
htdt/godogen
Generates game art from text prompts: PNG images, GLB 3D models, rigged characters, animations and sprites, with background removal.
A skill your agent uses 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…
$ npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install DRincs-Productions/pixi-vn pixi-vn-canvas --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/DRincs-Productions/pixi-vn.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/canvas .claude/skills/pixi-vn-canvas && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "pixi-vn-canvas" agent skill from https://github.com/DRincs-Productions/pixi-vn/tree/main/skills/canvas into .claude/skills/pixi-vn-canvas/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pixi-vn-canvas", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/DRincs-Productions/pixi-vn/tree/main/skills/canvasType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install DRincs-Productions/pixi-vn pixi-vn-canvas --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/DRincs-Productions/pixi-vn.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/canvas .agents/skills/pixi-vn-canvas && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "pixi-vn-canvas" agent skill from https://github.com/DRincs-Productions/pixi-vn/tree/main/skills/canvas into .agents/skills/pixi-vn-canvas/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pixi-vn-canvas", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install DRincs-Productions/pixi-vn pixi-vn-canvas --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/DRincs-Productions/pixi-vn.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/canvas .cursor/skills/pixi-vn-canvas && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "pixi-vn-canvas" agent skill from https://github.com/DRincs-Productions/pixi-vn/tree/main/skills/canvas into .cursor/skills/pixi-vn-canvas/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pixi-vn-canvas", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/DRincs-Productions/pixi-vn.git --path skills/canvas--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install DRincs-Productions/pixi-vn pixi-vn-canvas --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/DRincs-Productions/pixi-vn.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/canvas .gemini/skills/pixi-vn-canvas && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "pixi-vn-canvas" agent skill from https://github.com/DRincs-Productions/pixi-vn/tree/main/skills/canvas into .gemini/skills/pixi-vn-canvas/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pixi-vn-canvas", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install DRincs-Productions/pixi-vn pixi-vn-canvasInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/DRincs-Productions/pixi-vn.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/canvas .github/skills/pixi-vn-canvas && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "pixi-vn-canvas" agent skill from https://github.com/DRincs-Productions/pixi-vn/tree/main/skills/canvas into .github/skills/pixi-vn-canvas/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pixi-vn-canvas", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install DRincs-Productions/pixi-vn pixi-vn-canvas --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/DRincs-Productions/pixi-vn.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/canvas .opencode/skills/pixi-vn-canvas && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "pixi-vn-canvas" agent skill from https://github.com/DRincs-Productions/pixi-vn/tree/main/skills/canvas into .opencode/skills/pixi-vn-canvas/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "pixi-vn-canvas", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
pixi-vn-canvasA skill your agent uses 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…
Pixi Vn Canvas is an agent skill from DRincs-Productions/pixi-vn. 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.
Its SKILL.md is about 7.6k tokens, which your agent loads only when the skill is triggered. The skill folder holds 1 other file (for example `tickers.md`).
It sits in Game Development, covering Sprites and pixel art. The repository describes itself as: Create visual novels with a modern 2D rendering engine and your favorite JavaScript framework.
Read from SKILL.md and the folder at commit 01c19cb. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
No scripts in the folder and no shell commands in SKILL.md (its code samples are typescript).
From the folder's file list and the shell code blocks in SKILL.md.
Links to these hosts (documentation or services it may open):
pixi-vn.commotion.devgithub.comnpmjs.comFrom URLs in SKILL.md, links to its own repository left out.
Names no API keys, tokens, secrets or passwords.
From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Pixi Vn Canvas loads about 7.6k tokens when it runs. Until then it costs about 128 tokens; SKILL.md has 2,271 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from DRincs-Productions/pixi-vn at commit 01c19cb, republished under its LGPL-2.1 licence (© DRincs-Productions). 2,271 words, ~7,586 tokens.
.claude/skills/pixi-vn-canvas/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.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 (canvas, showImage, Sprite, transition helpers, etc.) is exported
from the main package entry point:
import { canvas } from "@drincs/pixi-vn";(Also available from the narrower @drincs/pixi-vn/canvas subpath — see pixi-vn-getting-started for when to prefer that.)
Load this skill whenever a task involves:
For building/mounting UI layers (HTML or PixiJS) on top of the canvas, use pixi-vn-ui instead —
this skill is about the gameLayer save-able scene graph, not UI chrome.
For dialogue/character-portrait logic use pixi-vn-characters and pixi-vn-narration instead;
this skill is about the underlying rendering primitives.
canvas (from @drincs/pixi-vn) is the single entry-point object developers use. It wraps
a PixiJS Application and exposes methods to manage canvas elements and layers. Call await canvas.init(element, options) once at startup (this is
normally done for you by Game.init(...) from the core package — see pixi-vn-getting-started).canvas.add(alias, component) inserts a component (an instance of Container, Sprite,
ImageSprite, ImageContainer, Text, or VideoSprite) into canvas.layers.gameLayer (a single
PixiJS Container that holds all "in-scene" elements) and sets component.label = alias. Use
canvas.find<T>(alias) to look elements back up and canvas.remove(alias) to remove them.
Aliases are also how Pixi'VN saves/restores canvas state (see pixi-vn-storage), so prefer the
alias-based helpers below over holding onto raw object references across steps.Container extends
PIXI.Container, Sprite/ImageSprite/VideoSprite extend PIXI.Sprite, Text extends
PIXI.Text. They add a .memory getter / .setMemory() for serialization, plus convenience
properties (anchor, align, percentagePosition, xAlign/yAlign, percentageX/percentageY)
as alternative ways to position an element without doing pixel math.Layer is just a type alias for a plain PIXI.Container<ContainerChild> — there's no
special Layer class. A separate, non-save-able PixiJS Container can be attached directly to the
stage as a sibling of gameLayer (canvas.layers.add/get/remove) — see pixi-vn-ui
for that API, it's how UI layers (HTML or PixiJS) are built on top of the canvas.canvas.animate(...)
(built on the motion 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 separate tickers singleton (also from @drincs/pixi-vn, not a member of
canvas — the old canvas.tickers is a deprecated alias of it).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 pixi-vn-assets for how
assets get registered (local vs. online) and loaded. addImage/showImage do also accept a raw
URL as a second argument for quick prototyping, but that couples code to a specific file location;
addImage/showImage throw a PixiError if neither a URL nor a registered alias resolves. Both
return an ImageSprite.
For a composite image made of multiple stacked textures (e.g. a character body + outfit + face),
use ImageContainer via addImageCointainer / showImageContainer (note the exported spelling
"Cointainer"):
import { 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) creates/replaces a Text element (extends PIXI.Text) and adds
it to the canvas immediately. options is TextOptions (PixiJS CanvasTextOptions plus the
align/percentagePosition positioning extensions), so style, fontSize, fill, x/y, etc.
all work as in plain PixiJS.
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 = 2addVideo/showVideo mirror addImage/showImage and return a VideoSprite (extends
ImageSprite). Files are also recognized as videos by extension automatically anywhere a
transition helper accepts an image URL (.mp4, .webm, .mov, etc. — see checkIfVideo).
Docs: pixi-vn.com/start/canvas-transition.
All transition helpers take (alias, componentOrUrl?, props?, priority?). If you omit the
component/URL argument, the alias itself is used as the texture URL/alias. Each function
replaces (or removes) whatever is currently registered under alias, transferring position and
running tickers from the old element automatically. They all return a Promise (or array) of
ticker ids you can pass to tickers.forceCompletion if you need to await completion, but
usually you just call and move on.
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 });props extends AnimationOptions from motion (e.g. duration, ease) plus a
completeOnContinue flag (default true) that finishes the transition immediately when the
player advances the narration before the animation ends — leave this at its default unless you
specifically want an animation to be interruptible/ignored.
These are only exposed through the transitions namespace (no flat top-level export like the
older moveIn/showWithDissolve), each as a matched xIn/xOut pair with the same
(alias, componentOrUrl?, props?, priority?) / (alias, props?, priority?) shapes as above.
They favor a handful of configurable options over narrative-specific variants — e.g. there's one
wipeIn, not wipeLeft/wipeRight.
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 (wipe/iris/split) or filter
(blur/pixelate/glitch/...) independently — e.g. call blurIn and then wipeIn 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 blurIn + showWithFade, a memory transition is a color overlay plus
blurIn, a "curtain" is a configured splitOut, and a diagonal wipe is just wipeIn/wipeOut
with a non-cardinal angle.
Docs: pixi-vn.com/start/canvas-transition#custom-functionality.
A custom transition is just a plain function that adds/replaces a component and drives it with
canvas.animate — the same primitive showWithDissolve, moveIn, etc. are built on:
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 canvas.add 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:
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
aliasToRemoveAfter: oldComponentAlias in canvas.animate's options instead of removing it
manually. To have the old component run its own transition-out (instead of a hard cut), give it a
second canvas.animate call paused with tickers.pause({ id }) and resumed via the new call's
tickerIdToResume option — see the wiki's own two worked examples for the exact sequencing.
Animating a filter's own property instead of a component property — for effects like blur,
pixelate, glow, or color grading, use filters.animate (from @drincs/pixi-vn/filters, available
since v1.9.4) instead of canvas.animate. It mirrors the same
(alias, keyframes, options, priority) shape with the Filter instance inserted as the second
argument; you attach the filter to component.filters yourself before animating, and detach +
destroy it in the cleanup callback (the 7th argument) once the animation completes — this is
exactly how transitions.blurIn/blurOut/pixelateIn/pixelateOut are implemented:
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.animate can also drive a plain numeric value with no live filter — pass undefined as
the filter and an apply callback (called every frame with the interpolated value) instead. This
is how wipeIn/irisIn/splitIn animate their mask geometry (a growing radius, a moving
boundary), since a mask has no filter property to write directly.
The effects namespace holds "articulated animations" — helpers built on top of canvas.animate
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, ...).
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 shakeEffect configured with a
small maxShockSize and a high shocksNumber (high-frequency, low-amplitude shaking).
The same effects namespace also has primitives built on the filters module (raw pixi-filters/
pixi.js filter classes, re-exported as filters.* - see @drincs/pixi-vn/filters) instead of
canvas.animate: 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 filters.animate, and detaches/destroys
the filter once done - the component is left exactly as it was before, same guarantee as every effect
above.
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 alias 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 filters.* class, attach it to
component.filters yourself, and drive it with filters.animate (see the low-level example just above
this section) - AdjustmentFilter/HslAdjustmentFilter (color grading), CRTFilter/OldFilmFilter
(retro looks), and BloomFilter/AdvancedBloomFilter (glow) are good starting points not covered above.
canvas.animate(componentOrAlias, keyframes, options, priority) is the primitive all transition
helpers are built on (motion's animate semantics: keyframes
are arrays of target values, options supports duration, ease, repeat, etc.). Pixi'VN tracks
animation state so it can be saved/restored — this is why you should prefer canvas.animate
(or the transition helpers) over driving PixiJS directly with your own requestAnimationFrame loop.
For UI that is not part of the saved scene graph (e.g. a PixiJS UI overlay), the docs recommend
importing the raw animate from @drincs/pixi-vn/motion instead — it skips the save-state
bookkeeping and is cheaper.
canvas.animate and the transition helpers above already use tickers internally — most tasks never
need to touch the ticker API directly. For a genuinely continuous/looping custom effect (no fixed
duration) or manual pause/resume/completion control over a running animation, see tickers.md
in this same skill folder (registering a Ticker, tickers.addSequence,
tickers.pause/resume/remove, tickers.completeOnStepEnd). Docs:
pixi-vn.com/start/canvas-tickers.
These optional packages are installed separately from @drincs/pixi-vn; 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-live2dUse this wrapper around untitled-pixi-live2d-engine for Live2D models. Register its render
plugin before Game.init() (or 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.Once the canvas is initialized, register the model asset and await model readiness before controlling it:
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 ImageSprite.load() for Live2D.ready.
@drincs/pixi-vn-spineUse this wrapper around @esotericsoftware/spine-pixi-v8 for skeletal animation. Add
import "@drincs/pixi-vn-spine"; 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.
Register the skeleton and atlas in the asset manifest, then load both before construction:
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.
Persistent UI chrome (HUD, menus) does not live on gameLayer — it lives on a separate,
non-save-able layer built with canvas.layers.add/get/remove (PixiJS-only UI) or
canvas.htmlLayers.add/get/remove (mounting a DOM-based UI framework like React
or Vue). That whole API, plus the official template's layer-naming conventions, extractImage() for
save-file thumbnails, and how to build a UI purely out of PixiJS components, is covered by
pixi-vn-ui — reach for that skill instead whenever the task is about UI rather than the game scene.
addImage/addVideo/addImageCointainer only construct and register the element — the
texture is not loaded/visible until you await element.load(). The show* variants
(showImage, showVideo, showImageContainer, and the transition helpers) call load() for
you; prefer them unless you need to prepare an element off-screen first.getTexture/load() throw a PixiError (unregistered_asset) if the alias can't be
resolved from the PixiJS Assets cache/manifest. See pixi-vn-assets for how to register an
alias (local assets via AssetPack, or online assets in src/assets/index.ts) before referencing it here.zIndex/tickers from the old one by default (canvas.add(alias, el, { ignoreOldStyle: true })
to opt out) — this is what lets showImage("bg", newUrl) "just work" as a same-alias swap.canvas.remove(alias) also removes tickers bound only to that alias; pass
{ ignoreTickers: true } if you intend to reattach them elsewhere first..on(...), not a Pixi'VN-specific method — a stray JSDoc
comment in the Sprite source suggests sprite.onEvent(...), but that method doesn't exist;
the official docs confirm
.on(...) is correct. The Pixi'VN-specific part is only the @eventDecorator() requirement
for save/load: sprite.on("pointerdown", Events.handler) only serializes correctly if
Events.handler is a static method decorated with @eventDecorator() (from @drincs/pixi-vn);
a plain inline arrow function will log a warning and not be restored after loading a save.x/y/position), anchor/pivot (where on the element itself the position point
sits), align/xAlign/yAlign (Ren'Py-style percentage-of-canvas positioning, e.g. 0.5 =
centered; per source JSDoc, pivot does not affect align), and
percentagePosition/percentageX/percentageY (also percentage-of-parent, but pivot does
affect it, unlike align). Setting x/align/percentagePosition on the same axis clears
the others; check element.positionType / element.positionInfo if you need to know which mode
is active.CANVAS_APP_GAME_LAYER_ALIAS ("__game_layer__") is reserved — canvas.add, remove, and
addLayer will refuse to use that alias.canvas.pause()/canvas.resume() stop/restart rendering and tickers for the whole game layer
(e.g. when opening a menu) — remember to call resume() or elements will appear frozen.Game.init(), and how the canvas is wired up at startup.completeOnContinue.addLayer, addHtmlLayer, and building UI screens with PixiJS components.© DRincs-Productions, LGPL-2.1. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 1 other file in skills/canvas of DRincs-Productions/pixi-vn.
Open the folder on GitHubat commit 01c19cb
Pixi Vn Canvas next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Pixi Vn Canvas this skillDRincs-Productions/pixi-vn | 149 | — | ~7.6k | Automated safety check: Pass | LGPL-2.1 | |
| Game Asset Generatorhtdt/godogen | 7.1k | — | ~2.8k | Automated safety check: Pass | MIT | |
| Code-Drawn 2D Game Art0x0funky/agent-sprite-forge | 4.4k | — | ~2.5k | Automated safety check: Pass | MIT | |
| Sprite Genaldegad/sprite-gen | 2.7k | — | ~4.9k | Automated safety check: Pass | Apache-2.0 | |
| Pixel Artmateaix/mateclaw | 1.2k | 5 repos | ~1.8k | Automated safety check: Pass | Apache-2.0 | |
| Petdexcrafter-station/petdex | 4.2k | — | ~614 | Automated safety check: Pass | MIT |
htdt/godogen
Generates game art from text prompts: PNG images, GLB 3D models, rigged characters, animations and sprites, with background removal.
0x0funky/agent-sprite-forge
Draws 2D game art from code with no image model: pixel sprites, SVG props and icons, rigged characters, FX, autotiles and layouts, only when explicitly asked for.
aldegad/sprite-gen
Generates images and game sprites through GPT or Grok with guided provider choices, separate saved defaults, automatic cleanup and optional curation.
mateaix/mateclaw
Pixel art w/ era palettes (NES, Game Boy, PICO-8). An agent skill from mateaix/mateclaw.
crafter-station/petdex
Browse, install, submit, and edit pixel-art pets with the Petdex CLI.
rehan-remade/universal-modder
Turn generated or hand-made art into exactly what a game engine loads.
DRincs-Productions/pixi-vn
A skill your agent uses when adding, organizing, registering, or loading non-code files (images, audio, video) in a Pixi'VN project — local assets processed by PixiJS AssetPack vs.
DRincs-Productions/pixi-vn
A skill your agent uses when defining visual novel characters for a @drincs/pixi-vn game — creating a character with a name, color, icon and other props, registering it so it can be looked up by id…
DRincs-Productions/pixi-vn
A skill your agent uses when implementing "go back" / "rewind" / step-navigation features in a Pixi'VN game, or when you need to read the player-facing dialogue/choice history (e.g.
DRincs-Productions/pixi-vn
A skill your agent uses when adding a minigame (snake, quiz, puzzle, timing/reaction game, ...) to a Pixi'VN visual novel — the useMinigame lifecycle hook pattern, using PixiJS directly on its own…
DRincs-Productions/pixi-vn
A skill your agent uses when writing or editing Pixi'VN story content — defining labels (scenes) with newLabel, writing dialogue steps, adding player choices with…
DRincs-Productions/pixi-vn
A skill your agent uses when implementing save/load in a Pixi'VN game — Game.exportGameState()/restoreGameState()/jsonToGameState(), what the exported GameState contains, and how to persist it (save…
Categories
A skill your agent uses 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…. Pixi Vn Canvas is an agent skill from DRincs-Productions/pixi-vn.animate), shake/animation effects, or ticker-based animations built on PixiJS.
Pixi Vn Canvas fits situations like: removing images; video on the PixiVN game canvas; creating transitions (dissolve; A custom one built on canvas.animate/filters.animate).
Run `npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a claude-code`. Or copy the skill folder (skills/canvas in DRincs-Productions/pixi-vn) into .claude/skills/pixi-vn-canvas in your project. Claude Code loads it when a task matches its description.
Run `npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a codex`. Or copy the skill folder (skills/canvas in DRincs-Productions/pixi-vn) into .agents/skills/pixi-vn-canvas in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add DRincs-Productions/pixi-vn --skill pixi-vn-canvas -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/pixi-vn-canvas, .gemini/skills/pixi-vn-canvas, .github/skills/pixi-vn-canvas and .opencode/skills/pixi-vn-canvas in your project.
SKILL.md names no scripts, command-line tools or credentials: Pixi Vn Canvas is instructions for the agent only.
SKILL.md names 4 domains. As links in the text: pixi-vn.com, motion.dev, github.com and npmjs.com. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Pixi Vn Canvas is published under the LGPL-2.1 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 7.6k tokens (SKILL.md is roughly 30k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Pixi Vn Canvas: Game Asset Generator (htdt/godogen, 7.1k stars), Code-Drawn 2D Game Art (0x0funky/agent-sprite-forge, 4.4k stars), Sprite Gen (aldegad/sprite-gen, 2.7k stars) and Pixel Art (mateaix/mateclaw, 1.2k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
DRincs-Productions (a GitHub organization) maintains it in DRincs-Productions/pixi-vn, which has 149 GitHub stars. The repository holds 13 skills in this directory. The repository was last updated on October 1, 2026.
Source: DRincs-Productions/pixi-vn on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.