Skip to content

Selectors

You can’t import Web UI’s components and hooks directly. Use these selectors to get them instead.

getComponents returns Web UI’s React components.

getComponents(): Components

Use the components to build your own interface, or decorate this selector to replace one with your own.

Example
const { getComponents } = getSelectors();
const { App, InkCanvas } = getComponents();

getControllerType returns the kind of game controller the reader has connected.

getControllerType(): { type: ControllerType }
type ControllerType = null | "generic" | "nintendo" | "playstation" | "xbox";

type is null when no controller is connected, and "generic" for a controller Web UI doesn’t recognize.

Example
const { getControllerType } = getSelectors();
const { type } = getControllerType();

getHooks returns Web UI’s React hooks.

getHooks(): Hooks
Example
const { getHooks } = getSelectors();
const { useLayers } = getHooks();

getI18nValue returns the interface text for a key, in the reader’s text language.

getI18nValue(context: {
key: string;
values?: Record<string, number | string>;
}): { value: string }

It looks up the key in Web UI’s own translations, first for the reader’s text locale, then for en-US. If a key has no entry, you get the key back as written, so a plain sentence works as its own key.

Each {{name}} in the text is replaced with values[name]. A placeholder with no value is left as written.

Example
const { getI18nValue } = getSelectors();
const { value } = getI18nValue({ key: "button", values: { index: 20 } });
// "Button 20"

getMenuComponent returns the component that wraps a menu. By default, it returns MenuPanel for every menu.

getMenuComponent(context: { schema: MenuSchema }): { component: unknown }

Decorate it to use your own component for a menu.

Example
decorateSelector("getMenuComponent", (context, next) => {
if (context.schema.name !== "journal") return next(context);
return { component: JournalMenu };
});

getMenuFieldComponent returns the component for a menu field. By default, Web UI provides a component for each field type.

getMenuFieldComponent(context: { field: MenuField }): { component: unknown }

The component receives props built from the field. Every field gets name, and label: the field’s text in the reader’s language. The other props depend on the field’s type:

Field typeProps
booleanvalue: boolean, setValue(newValue: boolean)
numbervalue: number, setValue(newValue: number), minimum?, maximum?, step?
stringvalue: string, setValue(newValue: string)
enumvalue: string, setValue(newValue: string), options: Array<{ label: string; value: string }>
buttonaction(): Promise<void>
bookmarkbookmark: null | Bookmark, locale: string, action(): Promise<void>
separatorOnly name and label

value is always current. The prop types are exported from @inkweaverdev/plugin-web-ui/plugin as MenuBooleanFieldProps, MenuEnumFieldProps, and so on.

For bookmark, locale is the reader’s text language.

Example
function Toggle({ label, setValue, value }) {
return (
<button onClick={() => setValue(!value)} type="button">
{label}: {value ? "On" : "Off"}
</button>
);
}
decorateSelector("getMenuFieldComponent", (context, next) => {
if (context.field.type !== "boolean") return next(context);
return { component: Toggle };
});

getRenderStats returns timings for the scene’s last twenty renders.

getRenderStats(): { renders: Array<RenderStats> }
type RenderStats = {
duration: number;
firstFrame: null | number;
frameCount: number;
frameInterval: null | { average: number; max: number };
frameTime: null | { average: number; max: number };
load: null | number;
outcome: "failed" | "interrupted" | "settled";
startedAt: number;
};

A render starts when the scene changes, and ends when its animations settle, a newer render replaces it, or it fails. Times are in milliseconds.

FieldDescription
durationFrom the start of the render to its end.
firstFrameFrom the start of the render until its first frame is on screen.
frameCountHow many frames were drawn.
frameIntervalThe time between one frame and the next.
frameTimeThe time spent drawing each frame.
loadThe time spent loading images and shaders.
outcomeHow the render ended.
startedAtWhen the render started, as a Date.now() timestamp.

firstFrame, frameInterval, frameTime, and load are null when the render ended before reaching them.

Example
const { getRenderStats } = getSelectors();
const { renders } = getRenderStats();
console.table(
renders.map(({ firstFrame, frameInterval }) => ({
firstFrame,
slowestFrame: frameInterval?.max,
})),
);