import * as historyUtils from '@drincs/pixi-vn/history'; export * from '@drincs/pixi-vn/history'; import * as narrationUtils from '@drincs/pixi-vn/narration'; import { NarrationGameState } from '@drincs/pixi-vn/narration'; export * from '@drincs/pixi-vn/narration'; import * as storageUtils from '@drincs/pixi-vn/storage'; export * from '@drincs/pixi-vn/storage'; import * as canvasUtils from '@drincs/pixi-vn/canvas'; export * from '@drincs/pixi-vn/canvas'; import * as characterUtils from '@drincs/pixi-vn/characters'; export * from '@drincs/pixi-vn/characters'; import { OnErrorHandler, GameUnifier } from '@drincs/pixi-vn/core'; export * from '@drincs/pixi-vn/core'; import { ApplicationOptions } from '@drincs/pixi-vn/pixi.js'; export { AllFederatedEventMap, ApplicationOptions, AssetSrc, AssetsBundle, AssetsManifest, FederatedEvent, LoadParserName, ResolvedAsset, ResolvedSrc, UnresolvedAsset } from '@drincs/pixi-vn/pixi.js'; import * as soundUtils from '@drincs/pixi-vn/sound'; export * from '@drincs/pixi-vn/sound'; export * from '@drincs/pixi-vn/tickers'; export * from '@drincs/pixi-vn/worker'; export { C as CachedMap } from './CachedMap-DZLvJAnA.cjs'; import { CanvasGameState } from './canvas.cjs'; import { HistoryGameState } from './history.cjs'; import { SoundGameState } from './sound.cjs'; import { StorageGameState } from './storage.cjs'; import { OpenedLabel } from './narration.cjs'; import { Devtools } from '@pixi/devtools'; import 'lru-cache'; import '@drincs/pixi-vn/filters'; import '@drincs/pixi-vn'; import './HistoryStep-WGB6nA4N.cjs'; import 'microdiff'; import 'tone'; import './StorageElementType-C7ETezlL.cjs'; /** * One error captured by {@link createGameTesting}'s `enable` while testing is active, via * `Game.addOnError`. */ interface GameTestingErrorEntry { error: unknown; timestamp: number; } /** * A read-only snapshot of everything a test session typically needs to decide its next * action, gathered from {@link narrationUtils.narration} and {@link historyUtils.stepHistory} * in a single call instead of reading several properties one by one. */ interface GameTestingState { dialogue: narrationUtils.DialogueInterface | undefined; dialogueGlue: boolean; choices: narrationUtils.StoredIndexedChoiceInterface[] | undefined; input: { isRequired: boolean; type: string | undefined; value: storageUtils.StorageElementType; }; canContinue: boolean; canGoBack: boolean; labelsOpened: narrationUtils.OpenedLabel[]; currentLabelId: string | undefined; stepCounter: number; } /** * The object attached to `window` (and returned) by `enable`. Every action method * merges the most recent props passed to `setProps` with any `extraProps` given here, * then delegates to the matching narration/history call — so calling these behaves exactly * like a real player action (the same `navigate`/`t`/`toast`/etc. the real UI uses). * * `narration`, `storage`, `stepHistory` and `Game` are also exposed directly for anything not * covered by the action methods (e.g. `storage.set(...)`, `Game.exportGameState()`). */ interface GameTestingAPI { readonly Game: TGame; readonly narration: narrationUtils.NarrationManagerInterface; readonly storage: storageUtils.StorageManagerInterface; readonly stepHistory: historyUtils.HistoryManagerInterface; /** * The most recent props passed to `setProps` — whatever your app's `StepLabelProps` * augmentation defines (e.g. `navigate`, `toast`). Useful to drive the app's UI directly * during a test session — e.g. `pixiVN.props.navigate("/settings")` — not just narration, * for full control over what's on screen. */ readonly props: narrationUtils.StepLabelPropsType; /** `Game.start` using the live props plus any `extraProps`. */ start(label: narrationUtils.LabelAbstract | narrationUtils.LabelIdType, extraProps?: Partial): Promise; /** {@link narrationUtils.NarrationManagerInterface.continue} using the live props plus any `extraProps`. */ continue(extraProps?: Partial, options?: { steps?: number; runNow?: boolean; }): Promise; /** {@link narrationUtils.NarrationManagerInterface.call} using the live props plus any `extraProps`. */ call(label: narrationUtils.LabelAbstract | narrationUtils.LabelIdType, extraProps?: Partial): Promise; /** {@link narrationUtils.NarrationManagerInterface.jump} using the live props plus any `extraProps`. */ jump(label: narrationUtils.LabelAbstract | narrationUtils.LabelIdType, extraProps?: Partial): Promise; /** * Selects the currently open choice with this `choiceIndex` (as seen in * `getState().choices`), using the live props plus any `extraProps`. * @throws when no open choice has that index. */ selectChoice(choiceIndex: number, extraProps?: Partial): Promise; /** Resolves a pending `narration.input.request(...)` with `value`, exactly like the player typing an answer and confirming. */ setInput(value: storageUtils.StorageElementType): void; /** {@link historyUtils.HistoryManagerInterface.back} using the live props plus any `extraProps`. */ goBack(extraProps?: Partial, options?: { steps?: number; }): Promise; /** {@link narrationUtils.NarrationLabelsInterface.closeCurrent} */ closeCurrentLabel(): void; /** {@link narrationUtils.NarrationLabelsInterface.closeAll}. **Can end the game.** */ closeAllLabels(): void; /** A snapshot of dialogue/choices/input/canContinue/canGoBack/labels — see {@link GameTestingState}. */ getState(): GameTestingState; /** All registered labels, including labels not currently open. */ getLabelIds(): narrationUtils.LabelIdType[]; /** Registered resolver aliases, including assets that have not been loaded. */ getAssetIds(): string[]; /** Present only when the application registers a screen navigation action. */ readonly navigate?: (screen: string) => Promise; /** Errors caught via `Game.addOnError` since `enable()` was called (or since the last {@link clearErrors}). */ readonly errors: GameTestingErrorEntry[]; clearErrors(): void; } /** * Per-action overrides an app can register via `setActions` so `Game.testing`'s * window-exposed actions run the app's own narration functions — with whatever UI-only side * effects they add (loading state, blocking while a menu is open, refreshing cached interface * data, ...) — instead of calling {@link narrationUtils.narration} / {@link * historyUtils.stepHistory} directly. Any action left undefined keeps the default behavior. * * `continue`/`back` take no arguments: the `extraProps`/`options` a caller passes to the * corresponding {@link GameTestingAPI} method are ignored when an override is registered, * since the override already has its own way to gather props (and typically doesn't support * stepped/replay options). `selectChoice` receives the resolved choice item instead of the * raw `choiceIndex`, since looking it up is already handled before the override runs. */ interface GameTestingActions { /** Optional router-independent screen navigation supplied by the application. */ navigate?: (screen: string) => Promise; continue?: () => Promise; back?: () => Promise; selectChoice?: (item: narrationUtils.StoredIndexedChoiceInterface) => Promise; start?: (label: narrationUtils.LabelAbstract | narrationUtils.LabelIdType, props?: T) => Promise; jump?: (label: narrationUtils.LabelAbstract | narrationUtils.LabelIdType, props?: T) => Promise; call?: (label: narrationUtils.LabelAbstract | narrationUtils.LabelIdType, props?: T) => Promise; } declare let version: string; /** * Is a special alias to indicate the game layer. */ declare const CANVAS_APP_GAME_LAYER_ALIAS = "__game_layer__"; declare const SYSTEM_RESERVED_STORAGE_KEYS: { /** * The key of the current dialogue memory */ CURRENT_DIALOGUE_MEMORY_KEY: string; /** * The key of step counter of the current dialogue memory */ LAST_DIALOGUE_ADDED_IN_STEP_MEMORY_KEY: string; /** * The key of the current menu options memory */ CURRENT_MENU_OPTIONS_MEMORY_KEY: string; /** * The key of the last menu options added in the step memory */ LAST_MENU_OPTIONS_ADDED_IN_STEP_MEMORY_KEY: string; /** * The key of the input memory. This value can be read by pixi-vn json importer */ CURRENT_INPUT_VALUE_MEMORY_KEY: string; /** * The key of the last input added in the step memory */ LAST_INPUT_ADDED_IN_STEP_MEMORY_KEY: string; /** * The key of the current input info */ CURRENT_INPUT_INFO_MEMORY_KEY: string; /** * The key of the characters memory */ CHARACTER_CATEGORY_KEY: string; /** * This variable is used to add the next dialog text into the current dialog memory. * This value was added to introduce Ink Glue functionality https://github.com/inkle/ink/blob/master/Documentation/WritingWithInk.md#glue */ ADD_NEXT_DIALOG_TEXT_INTO_THE_CURRENT_DIALOG_FLAG_KEY: string; /** * The key of a list of all labels that have been opened during the progression of the steps. */ OPENED_LABELS_COUNTER_KEY: string; /** * The key of a list of all choices that have been made during the progression of the steps. */ ALL_CHOICES_MADE_KEY: string; /** * The key of the current step times counter. * This value was added to introduce Ink Sequences, cycles and other alternatives https://github.com/inkle/ink/blob/master/Documentation/WritingWithInk.md#sequences-cycles-and-other-alternatives */ CURRENT_STEP_TIMES_COUNTER_KEY: string; /** * The key of the last dialogue step glued in the step memory */ LAST_STEP_GLUED: string; }; interface GameState { pixivn_version: string; stepData: NarrationGameState; storageData: StorageGameState; canvasData: CanvasGameState; soundData: SoundGameState; historyData: HistoryGameState; path: string; } /** * It is a interface that contains the information of a step. */ interface GameStepStateData { /** * The browser path that occurred during the progression of the steps. */ path: string; /** * The storage that occurred during the progression of the steps. */ storage: StorageGameState; /** * The index of the label that occurred during the progression of the steps. */ labelIndex: number; /** * The canvas that occurred during the progression of the steps. */ canvas: CanvasGameState; /** * The opened labels that occurred during the progression of the steps. */ openedLabels: OpenedLabel[]; /** * The sound data that occurred during the progression of the steps. */ sound: SoundGameState; } /** * This function is used to create a deep copy of the element * @param element The element to be copied * @returns The copied element * @throws {PixiError} when the element is not JSON serializable (e.g. contains functions or class instances). */ declare function createExportableElement(element: T): T; declare namespace Game { /** * Initialize the Game and PixiJS Application and the interface div. * This method should be called before any other method. * @param element The html element where I will put the canvas. Example: document.body * @param width The width of the canvas * @param height The height of the canvas * @param options Equivalent to the options you can use when initializing a [PixiJS Application](https://pixijs.com/8.x/guides/components/application). Additionally, it supports the following options: * - `id`: The id of the canvas element. * - `navigate`: The route navigate function. * - `resizeMode`: The resize mode of the canvas. * @param devtoolsOptions Equivalent to the options you can use when initializing the [PixiJS Devtools](https://pixi-vn.com/start/canvas#use-pixijs-devtools-with-pixivn). * @example * ```ts * const body = document.body * if (!body) { * throw new Error('body element not found') * } * await Game.initialize(body, { * navigate: (path) => { * // navigate to the path * }, * width: 1920, * height: 1080, * backgroundColor: "#303030" * resizeMode: "contain" * }) * ``` */ function init(element: HTMLElement, options: Partial & { /** * The id of the canvas element. It will be used to create the canvas element and to reference it. * @default "pixi-vn-canvas" */ id?: string; /** * The route navigate function. * You can set this function after the initialization using {@link GameUnifier.navigate} * @param path The path to navigate to. * @returns */ navigate?: (path: string) => void | Promise; /** * The resize mode of the canvas. Possible values are: * - `none`: No resizing. * - `contain`: The canvas will be resized to fit within the parent element while maintaining its aspect ratio. (default) * @default "contain" */ resizeMode?: "contain" | "none"; }, devtoolsOptions?: Devtools): Promise; /** * Initialize only the GameUnifier, and not the PixiJS Application and the interface div. * This method can be used if you want to use only the GameUnifier features, such as save/load game, * without initializing the canvas. */ function init(): Promise; /** * Clear all game data. This function is used to reset the game. */ function clear(): void; /** * Get all the game data. It can be used to save the game. * @returns The game data */ function exportGameState(): Promise; /** * Load the save data * @param data The save data object to restore the game state from. */ function restoreGameState(data: GameState): Promise; /** * Start the game with a label. This function will clear all the game data and start the narration from the specified label. * @param label The label to start the game with. It can be a string or a LabelAbstract instance. If it is a string, it will be used as the id of the label to start. If it is a LabelAbstract instance, it will be used directly. If the label is not found, an error will be thrown. * @param props The properties to pass to the label. It will be passed to the {@link StepLabelType} of the label when it is executed. * @returns The result of the label execution. It can be a {@link StepLabelResultType} or a Promise that resolves to a {@link StepLabelResultType}. */ function start(label: narrationUtils.LabelAbstract | narrationUtils.LabelIdType, props: narrationUtils.StepLabelPropsType): Promise; /** * Convert a JSON string to a save data * @param json The JSON string * @returns The save data */ function jsonToGameState(json: string): GameState; /** * Function to be executed at the end of the game. It should be set in the game initialization. * @example * ```ts * Game.onEnd(async (props) => { * props.navigate("/end") * }) * ``` */ function onEnd(value: narrationUtils.StepLabelType): void; /** * Register an error handler. Multiple handlers can be registered; they * will be executed in registration order. * * You can also check if the error is an instance of {@link PixiError} to handle specific errors related to Pixi’VN. * * @example * ```ts * // Register a synchronous error handler * Game.addOnError((error, props) => { * props.notify("An error occurred") * // send a notification to GlitchTip, Sentry, etc... * }) * * // Register an error handler for Pixi’VN specific errors * Game.addOnError((error, { notify }) => { * if (error instanceof PixiError) { * // ... * } * }); * * // Register an asynchronous error handler * Game.addOnError(async (error, props) => { * await logErrorToServer(error) * props.notify("An error occurred") * }) * * // Register an error handler with step restoration/rollback * Game.addOnError(async (error, props) => { * // Restore the game state to the previous step * await stepHistory.back(props) * props.notify("An error occurred, returning to previous step") * }) * ``` */ function addOnError(value: OnErrorHandler): () => void; /** * Remove a previously registered error handler. */ function removeOnError(handler: OnErrorHandler): void; /** * Is a function that will be executed before any step is executed. * @param stepId The index of the `step` being executed * @param label The `label` containing the `step` * @returns */ function onStepStart(value: (stepId: number, label: narrationUtils.LabelAbstract) => void | Promise): void; /** * Is a function that will be executed in {@link onStepStart} if the id of the step is 0 * and when the user laods a save file. * When you load a save file, will be executed all onLoadingLabel functions of the {@link narrationUtils.narration}.openedLabels. * It is useful for example to make sure all images used have been cached * @param stepId The index of the `step` being executed * @param label The `label` being executed * @returns * @example * ```ts * Game.onLoadingLabel(async (stepId, label) => { * await Assets.load('path/to/image1.png') * await Assets.load('path/to/image2.png') * }) * ``` */ function onLoadingLabel(value: (stepId: number, label: narrationUtils.LabelAbstract) => void | Promise): void; /** * Is a function that will be executed when the step ends. * @param stepId The index of the `step` that ended * @param label The `label` containing the `step` * @returns */ function onStepEnd(value: (stepId: number, label: narrationUtils.LabelAbstract) => void | Promise): void; /** * Is a function that will be executed every time a label is about to be started, either via * `narration.call`, `narration.jump`, or a choice of type `"call"` / `"jump"`. * * By default (when this is not set), the label starts immediately, exactly like before this hook * existed. If you set it, you take control: call `defaultStart()` yourself whenever you actually * want the label to run — right away, or later (e.g. on a subsequent player action in your * template). Until `defaultStart()` is called, nothing about the label happens: it is not added to * the history and no step of it runs. * @example * ```ts * Game.onLabelStarting((labelId, props, options, defaultStart) => { * pendingLabelStart = defaultStart; // keep it for later, don't run it now * }) * ``` */ function onLabelStarting(value: (labelId: narrationUtils.LabelIdType, props: narrationUtils.StepLabelPropsType, options: { choiceMade?: number; closeCurrentLabel?: boolean; type: string; }, defaultStart: () => Promise) => narrationUtils.StepLabelResultType | Promise): void; /** * Is a function that will be executed every time the current label is about to close because it * naturally ran out of steps and control is returning to the label that called it. * * By default (when this is not set), the label closes immediately, exactly like before this hook * existed. If you set it, you take control: call `defaultClose()` yourself whenever you actually * want the label to close — right away, or later (e.g. on a subsequent player action in your * template). Until `defaultClose()` is called, the label stays open and narration does not * continue into the parent label. * * This does not fire for a `jump` or a choice's `closeCurrentLabel` option - those close the * current label as part of starting a new one, so {@link onLabelStarting} already covers * deferring them. * @example * ```ts * Game.onLabelClosing((labelId, props, defaultClose) => { * pendingLabelClose = defaultClose; // keep it for later, don't run it now * }) * ``` */ function onLabelClosing(value: (labelId: narrationUtils.LabelIdType, props: narrationUtils.StepLabelPropsType, defaultClose: () => Promise) => narrationUtils.StepLabelResultType | Promise): void; /** * Function to be executed when navigation is requested. * @example * ```ts * Game.onNavigate(async (path) => { * // custom navigation logic * window.history.pushState({}, "title", path) * }) * ``` */ function onNavigate(value: (path: string) => void | Promise): void; /** * Register a handler to run immediately before a narration "continue" operation. * Handlers are executed in registration order and may be async. Use * `{@link addOnPreContinue}` / `{@link removeOnPreContinue}` to manage them programmatically. */ function addOnPreContinue(handler: () => Promise | void): void; function removeOnPreContinue(handler: () => Promise | void): void; /** * Optional integration point for offloading Pixi'VN's own heavy, pure computations (state * diffing/restoring/cloning for `stepHistory.back()`/`add()`/`export()`) to a Worker the game * project provides. Pixi'VN never creates a Worker itself, decides on its own which eligible * work actually goes through it, and falls back to computing the same thing synchronously * on the main thread whenever none is registered - so projects that can't or don't want to * use Workers (SSR, certain embeds, ...) are unaffected either way. * * The game project stays in control of the actual `new Worker(...)` call (bundler-specific * URL/`type: "module"` handling, CSP, lifecycle) and only needs to point that worker's * message handling at `handleGameWorkerMessage` from `@drincs/pixi-vn/worker`: * * ```ts * // main thread * import { Game } from "@drincs/pixi-vn"; * const worker = new Worker(new URL("./game-worker.ts", import.meta.url), { type: "module" }); * Game.worker.register(worker); * * // game-worker.ts * import { handleGameWorkerMessage } from "@drincs/pixi-vn/worker"; * self.onmessage = async (event) => { * const response = await handleGameWorkerMessage(event.data); * if (response) self.postMessage(response); * }; * ``` * * A third-party library built on top of Pixi'VN (one with `@drincs/pixi-vn` as a peer * dependency) can share this same worker for its own heavy, pure computations instead of * needing one of its own - see `registerGameWorkerHandler` (worker side) and * `GameWorkerManager.custom` (main-thread side), both from `@drincs/pixi-vn/worker`. */ const worker: { register: (worker: Worker) => void; unregister: () => void; readonly isAvailable: boolean; }; /** * Lets an AI agent (or any external script/browser console) drive and inspect a running game * through `window`, without needing to know the app's own UI wiring. Not enabled by default — * something must opt in, typically only in development. Two pieces are needed: * - `enable()`/`disable()` turn the `window` bridge on/off — the `@drincs/pixi-vn/vite` plugin's * `testing` option does this automatically while its dev server is running, with no extra code. * - `setProps(props)` keeps the live app props (`navigate`/`t`/`toast`/etc.) available to every * action — call it unconditionally from wherever your app builds those props (e.g. at the end * of a `useGameProps()`-style hook), since every action needs up-to-date props whether or not * testing happens to be enabled right now. * - `setActions(actions)` is optional: if the app wraps `narration`/`stepHistory` in its own * functions to handle UI-only concerns (a loading indicator, blocking while a menu is open, * refreshing cached interface data, ...), it can register those functions so `continue()`, * `goBack()`, `selectChoice()`, `start()`, `jump()` and `call()` drive the game through them * instead of calling `narration`/`stepHistory` directly — same as a real player action would. * See the `pixi-vn-testing` skill for the full guide (activation patterns, the complete command * surface, and cookbook snippets for a browser-driven test session). */ const testing: { setProps: (props: narrationUtils.StepLabelPropsType) => void; setActions: (actions: GameTestingActions) => void; enable: (options?: { windowKey?: string; } | undefined) => GameTestingAPI; disable: () => void; isEnabled: () => boolean; }; } declare const _default: { canvas: canvasUtils.CanvasManagerInterface; narration: narrationUtils.NarrationManagerInterface; sound: soundUtils.SoundManagerInterface; storage: storageUtils.StorageManagerInterface; tickers: canvasUtils.CanvasTickersInterface; history: historyUtils.HistoryManagerInterface; Game: typeof Game; GameUnifier: typeof GameUnifier; createExportableElement: typeof createExportableElement; characterUtils: typeof characterUtils; canvasUtils: typeof canvasUtils; narrationUtils: typeof narrationUtils; soundUtils: typeof soundUtils; CANVAS_APP_GAME_LAYER_ALIAS: string; PIXIVN_VERSION: string; }; export { CANVAS_APP_GAME_LAYER_ALIAS, Game, version as PIXIVN_VERSION, SYSTEM_RESERVED_STORAGE_KEYS, createExportableElement, _default as default }; export type { GameState, GameStepStateData, GameTestingAPI, GameTestingActions, GameTestingErrorEntry, GameTestingState };