drincs-productions/pixi-vn/testing
Claude Code and agent skill by drincs-productions/pixi-vn
- community
Checking that the SKILL.md file is still in the repository.
Use when an AI agent (or any external script) needs to play-test a running Pixi'VN game end-to-end in a real browser — starting the game, advancing/branching the story, answering input prompts, going back, and reading/writing storage — via `Game.testing`, the opt-in devtools bridge exposed on `window`. Load this before wiring up automated/agent-driven playtesting, not for authoring story content itself (see `pixi-vn-narration`).
Install
npx vskill@latest install drincs-productions/pixi-vn/testingSKILL.md
Pixi'VN Testing module
When to use this skill
Use this skill when the task is to play the game from the outside — driving it like a player would, but from a script or an AI agent evaluating JavaScript in the page, instead of clicking UI. Typical asks this covers: "start the game and play through label X", "verify choice B leads to ending Y", "check that this bug repros after going back three steps", "seed storage with gold: 100 and confirm the shop unlocks", "run this game headless as a regression test".
This assumes the game's dev server (or a build served on a URL) and a browser are already running/reachable — starting either one is outside this skill; it only covers the game-control API itself. Do not use this skill for writing story content (pixi-vn-narration), save-file persistence (pixi-vn-saves), or the go-back UI/internals (pixi-vn-history) — those are the modules this skill drives, not what it teaches.
1. Why you can't just call narration.continue({}) from the console
narration.continue, .call, .jump, narration.choices.select, and stepHistory.back all take a props argument typed as StepLabelProps — the exact object a real game passes from its UI layer. Most real projects augment StepLabelProps (via TS module augmentation, see pixi-vn) with app-specific fields: a router navigate, an i18n t, a toast, etc. (the official React template does exactly this — see pixi-vn-narration section 9). If a step calls props.navigate(...) or props.t(...), passing {} from a console/script call throws immediately.
Game.testing solves this once: the app pushes its real, live props to it (via setProps, see below) wherever it already builds them, and every action it exposes merges those in before delegating — so agent-driven calls behave exactly like a real player action, with no need to reconstruct or fake the app's props shape.
2. Enabling it
Game.testing is opt-in and disabled by default, and nothing about it depends on any particular bundler (Vite, Webpack, or none at all). Two independent pieces make it work:
- Turning the `window` bridge on/off —
Game.testing.enable(options?)/.disable(). - Keeping it supplied with live props —
Game.testing.setProps(props).
Turning it on/off
If the project uses @drincs/pixi-vn/vite's vitePluginPixivn, this is already handled: its testing option defaults to `true`, auto-enabling Game.testing for as long as vite dev keeps running (by injecting a small module into index.html) — never during vite build, regardless of the option. No app code needed for this part:
Pass testing: false if you don't want this — e.g. a dev server shared with other people that you don't want remote-controllable.
Without the Vite plugin (a different bundler, or no bundler-level integration at all), call it yourself, gated behind your own dev-only check:
options.windowKey(default"pixiVN") — the property name the API is attached under onwindow.- Returns the same API object it attaches to
window[windowKey], in case you want to keep a direct
reference instead of going through window.
- Calling
enableagain (e.g. on hot reload) replaces the previous session instead of stacking. Game.testing.disable()tears it down (detaches fromwindow, stops capturing errors).Game.testing.isEnabled()reports whether a session is currently active.
Only enable this when you actually want the game remote-controllable. It hands out full control over game state (see §4) to anything that can run JavaScript in that page — treat it like any other devtools/debug backdoor.
Keeping it supplied with live props: setProps
Call Game.testing.setProps(props) unconditionally, wherever your app already builds its StepLabelProps — it's a cheap assignment, safe to call whether or not testing happens to be enabled right now, and every Game.testing action reads through whatever was passed here most recently:
React template convention
The official React template's useGameProps() (src/lib/hooks/props-hooks.ts — see pixi-vn-narration section 9) already ends with exactly that Game.testing.setProps(props) call, and vite.config.ts's vitePluginPixivn(...) call needs no extra option — testing defaults to true. Since useGameProps() already runs on every render of every component that needs game props, this is the only line the template needs: no dedicated bridge component, no manual enable() call.
Routing through the app's own narration functions: setActions
Most real apps don't call narration.continue/stepHistory.back/etc. straight from a "next" button — they wrap them in their own functions that also handle UI-only concerns a test session should trigger too: a loading indicator, refusing to advance while a menu/dialog is open, refreshing cached interface data after the step resolves, and so on. By default Game.testing's actions skip all of that and call narration/stepHistory directly, so an agent driving the game through window.pixiVN can get out of sync with what the real UI would have done (e.g. it never sees the loading state, or advances past a guard the real "next" button respects).
Game.testing.setActions(actions) fixes this: register the app's own functions once, and continue()/goBack()/selectChoice()/start()/jump()/call() call them instead. Any action left out keeps calling narration/stepHistory directly, so this is opt-in per action:
Mount that hook once near the app root (same idea as useGameProps() always calling setProps) and window.pixiVN.continue() now runs the exact same code path as a player clicking "next".
A few things follow from continue/back taking no arguments themselves:
- The
extraProps/optionsa caller passes towindow.pixiVN.continue(...)/
window.pixiVN.goBack(...) are ignored once an override is registered — the override manages its own props (typically via setProps) and usually has no notion of { steps, runNow }. Drive those through window.pixiVN.props/narration/stepHistory directly if you need that level of control.
selectChoice's override receives the already-resolved choice item (the same shape as
getState().choices[i]), not the raw choiceIndex — the lookup (and the "no open choice with that index" error) still happens before the override runs.
setActionsis safe to call whether or not testing is enabled yet, safe to call again to update the
registered functions, and persists across disable()/enable() — same as setProps.
3. Driving the game
Every action below reads through window.pixiVN (or your custom windowKey), evaluated in the page — e.g. via a browser automation tool's "evaluate script" capability, or by pasting into the devtools console by hand. If the Chrome DevTools MCP server is available, prefer it over any other browser automation for this: evaluate_script runs the snippets below directly in the page, navigate_page/ click/take_snapshot drive UI the game itself doesn't expose through window.pixiVN (e.g. a login screen), take_screenshot lets you actually look at the canvas instead of only trusting getState(), and list_console_messages surfaces errors/warnings a script-only check would miss — checking console output after every meaningful step, not just at the end, has caught real bugs (e.g. a framework deprecation warning) that a headless script relying only on errors/return values missed. Fall back to a Playwright/chromium-cli script, or another MCP browser tool, only when Chrome DevTools MCP isn't available. All of the actions below are async except setInput, closeCurrentLabel/ closeAllLabels, and getState.
Every action accepts an optional second extraProps argument (first argument for selectChoice's props is its second argument, continue/goBack's is first) that's shallow-merged on top of the live props for that one call — useful to override just one field (e.g. a fake navigate to observe where the game tried to go) without touching the app's real wiring:
Reading state before deciding the next action
Don't act blindly — read getState() first to see what's actually on screen and what actions are valid right now:
- If
choicesis set, callselectChoice(choiceIndex)— don't callcontinue(), it won't advance
past an open choice menu.
- If
input.isRequiredistrue, callsetInput(value)before the nextcontinue(). - If
canContinueisfalsefor any other reason, a step is mid-flight (e.g. an async transition) —
wait and re-check rather than firing another action immediately.
Driving the app's UI directly, not just narration
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 reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/testing/SKILL.md
Popularity
- Repository stars
- 149
- 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/testing)