drincs-productions/pixi-vn/narration
Claude Code and agent skill by drincs-productions/pixi-vn
- community
Checking that the SKILL.md file is still in the repository.
Use when writing or editing Pixi'VN story content — defining labels (scenes) with newLabel, writing dialogue steps, adding player choices with newChoiceOption/newCloseChoiceOption, conditional/branching labels, or wiring up narration.call/jump/continue and Game.start to progress the story.
Install
npx vskill@latest install drincs-productions/pixi-vn/narrationSKILL.md
Pixi'VN Narration module
When to use this skill
Use this skill whenever the task is about the story itself: creating a new scene/label, writing a line of dialogue, adding a menu of player choices, branching a label's content based on game state, or driving story progression (starting the game, moving to the next step, calling/jumping between labels). This is the core engine of Pixi'VN — almost every "write a scene" or "add a choice" request touches this module.
Do not use this skill for: character definitions/appearance (see pixi-vn-characters), undo/go-back mechanics (see pixi-vn-history), save files (see pixi-vn-saves), or persistent game variables (see pixi-vn-storage).
Official docs for this module: https://pixi-vn.com/start/narration (overview), https://pixi-vn.com/start/labels and https://pixi-vn.com/start/labels-flow (labels/steps/flow), https://pixi-vn.com/start/labels-advanced (hooks, dynamic steps), https://pixi-vn.com/start/dialogue, https://pixi-vn.com/start/choices, https://pixi-vn.com/start/input.
Optional runtime AI: @drincs/pixi-vn-ai
For dialogue or images generated during play, install the separate @drincs/pixi-vn-ai package and its required peers; import its ai singleton from that package. This API is experimental: check the installed types before implementing provider-specific options.
Await ai.init(...) once during startup. Without options it downloads a local WebLLM text model in the browser; image generation still needs an external provider. Configure textProvider and/or imageProvider for AI SDK models, or use ComfyUIImageModel from @drincs/pixi-vn-ai/comfyui with a ComfyUI API-format workflow for images.
In an async label step, generate the text and assign it to the usual dialogue state:
ai.image.generateBackground and ai.image.generateElement generate scene imagery; the library builds prompts from the request and structured context. Consult the AI guide and plugin README for dependencies, provider configuration, image results, and display helpers before wiring images into canvas. For exact signatures and types, see the plugin's JSDoc reference: jsdocs.pixi-vn.com/pixi-vn-ai.
1. Defining a label
A label is the Pixi'VN equivalent of a Ren'Py "bookmark"/landmark in the story (the same concept is called a knot in the _ink_ language): a container for an ordered list of steps (plain functions), each one run when the player advances the story. Labels are created with newLabel and are automatically registered so they can be referenced by id anywhere (choices, narration.call, narration.jump, Game.start).
Key points:
newLabel(id, steps, props?)—idmust be unique across the whole game;stepsis an array of
StepLabelType functions, executed in order as the player continues; props is optional (onStepStart, onStepEnd, onLoadingLabel hooks — rarely needed for basic authoring).
- Each step is
(props, { labelId }) => StepLabelResultType | Promise<StepLabelResultType>. Steps
can be async when they need to await something (e.g. calling another label, loading assets). Return value is optional — most steps return nothing (void); returning a string/object is only needed by code that consumes StepLabelResultType explicitly.
- Every label file should call
newLabel(...)at module scope so the label registers itself simply
by being imported. Make sure the module gets imported somewhere reachable at startup.
stepscan also be a function that returns the array, e.g.() => [...], which lets step
content change dynamically based on game state — see "Conditional branching" below.
2. Dialogue
Set narration.dialogue inside a step to display a line. It accepts either a plain string/array of strings, or a DialogueInterface-shaped object with text and an optional character:
Which form to prefer depends on the project's setup — see pixi-vn-characters for the full rationale, but in short: prefer the instance unless the @drincs/pixi-vn/vite plugin's typeFilePath generation (narrowing CharacterIdType to known ids, see pixi-vn) is set up, in which case prefer the string-id form — it's just as typo-safe then, without needing to import the character module in every label file.
narration.dialogue is a getter too: reading it returns { text, character } (with character resolved to the full CharacterInterface when a registered id was used, or undefined/the raw string otherwise).
Gluing dialogue across steps: set narration.dialogGlue = true _before_ assigning narration.dialogue in a step to have that line's text appended to the current dialogue text instead of replacing it. This lets a paragraph be split across several steps (each free to change a character's pose/sprite in between) while it reads to the player as one continuous block of text, with no waiting/empty-box flash in between. From the official React template (src/content/labels/second.label.ts):
The player still advances one step at a time as usual (dialogGlue only affects how the _text_ accumulates, not whether continue()/player input is needed); it resets automatically once a non-glued narration.dialogue assignment is made.
Character objects (CharacterBaseModel and registration via RegisteredCharacters) are covered by the pixi-vn-characters skill — this module only needs a character's id (or the object) to attach it to a line.
Docs: https://pixi-vn.com/start/dialogue
3. Rich text: Markdown and HTML in dialogue
Docs: pixi-vn.com/start/markup, markup-markdown, markup-tailwindcss.
Pixi'VN isn't tied to any markup language for narration.dialogue text, but Markdown is the recommended one, and Markdown can be freely mixed with raw HTML for anything Markdown itself can't express. Every official template already renders dialogue this way — in the React template specifically, via react-markdown with the remark-gfm (GFM tables/strikethrough/etc.) and rehype-raw (allows raw HTML inside the Markdown source) plugins:
When writing dialogue text, default to plain Markdown's classic inline styles — *italic*, **bold**, and similar simple emphasis — rather than reaching for raw HTML/CSS. Only use HTML (or anything fancier) when the user actually asks for it (e.g. a specific color, an animation, an underline a specific character always has):
When HTML is asked for, the recommended CSS approach (per the docs) is Tailwind CSS — already installed and configured in every official template, optionally with plugins like @tailwindcss/typography, tw-animate-css, or tailwind-animations for richer text effects. A Tailwind-styled inline element inside dialogue text must be `inline-block` — a plain inline element won't apply transform/animation utilities correctly mid-paragraph:
4. Choices
A choice menu is created by assigning an array to narration.choices, typically built with newChoiceOption (opens another label) and/or newCloseChoiceOption (just closes the menu and lets the current label's next step run).
newChoiceOption(text, label, props, options?)—textis the option's label text;labelis the
target Label object or its string id; props are passed to the target label's steps (pass {} if none are needed); options.type is "call" (default — the target runs and can return to this label afterwards) or "jump" (the current label is closed first, no return).
newCloseChoiceOption(text, options?)— closes the choice menu without opening any label; narration
simply continues into the current label's next step. options.closeCurrentLabel: true additionally closes the current label when chosen.
- Other
ChoiceInterfaceoptions available in both:oneTime(option disappears once chosen),
onlyHaveNoChoice (shown only as a fallback if every other option has been removed), autoSelect (if it ends up being the only available option, it's chosen automatically without player input).
- Read
narration.choices.list(aStoredChoiceInterface[], an indexed array — each option carries
a choiceIndex), and call narration.choices.select(choice, props) when the player picks one. Pass through any StepLabelProps the target label needs plus the option's own stored props:
choices.select dispatches to narration.call/narration.jump/closing the menu based on the chosen option's type, and records the pick so narration.queries.alreadyCurrentStepMadeChoices / queries.timesChoiceMade can reflect past choices (useful for oneTime options across replays).
Docs: https://pixi-vn.com/start/choices
5. Progressing and closing labels
Docs: https://pixi-vn.com/start/labels-flow
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/narration/SKILL.md
Popularity
- Repository stars
- 137
- Repository forks
- 8
- 7-day trend score
- 25
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/drincs-productions/pixi-vn/narration)