Voxta docs

HUD & stage effects

Game UI on the stage — a player HUD, windows, popups, screen effects and combat feedback.

A family of app triggers that turn the stage view into a game screen: a stat HUD, spawnable windows, splash banners, modal choices, and screen effects.

All of it is shown to the player only — none of it reaches the AI. If the character should know something, say it with a context or a note.

The HUD

SetHud replaces the HUD with a list of typed sections. Keep it in a chat variable so it persists, and re-push it on resume — the on-screen HUD is not restored after a refresh.

import { chat } from "@voxta";

function renderHud() {
  const hud = chat.get("hud", null);
  if (hud) chat.appTrigger("SetHud", hud);
}

chat.addEventListener("start", () => {
  chat.set("hud", {
    title: "Adventurer",
    sections: [
      { type: "badge", label: "Location", items: [{ label: "Moonlit Tavern", icon: "📍" }] },
      { type: "bars", label: "Stats", icon: "📊", items: [
        { label: "Health", value: 72, max: 100, icon: "❤️", color: "#e5484d" },
      ]},
    ],
  });
  renderHud();
});

chat.addEventListener("resume", renderHud);

Each section is a tab, except badge sections which render in a persistent footer.

Section typeRenders
barsValue/max fill. Add min below zero for a diverging gauge.
chipsStatus pills. qty shows ×N.
gridInventory slots. Supports price.
checklistObjectives, with done.
badgeA single footer line.

Every item takes label, icon (emoji or short text), color, tooltip. Set showWhenCollapsed: true on a section to keep it visible when the player collapses the HUD.

ShowHud, HideHud and ToggleHud take no arguments.

If the scenario inherits the Voxta UI parent, import { hud } from "../base/hud" gives you set, push, setBar, damage, heal, addItem, removeItem, complete, setBadge instead of the manual get/set/push round-trip.

Item actions

Give an item an actions list and it gets a context menu. Picking one fires app:hud_action with { action, item, section }.

{ label: "Health Potion", icon: "🧪", qty: 3, actions: [
  { id: "drink", label: "Drink", icon: "🧪" },
  { id: "drop",  label: "Drop",  icon: "🗑️" },
]}

chat.addEventListener("app:hud_action", (e) => {
  const { action, item } = e.arguments;
  // ...
});

Windows

A window is a movable surface separate from the HUD — a shop, a loot pile, a container. Several can be open at once. Windows are transient: re-open them when needed rather than restoring on resume.

chat.appTrigger("OpenPanel", {
  id: "shop:blacksmith",
  title: "Blacksmith",
  anchor: "center",
  sections: [
    { type: "grid", label: "Wares", items: [
      { label: "Iron Sword", icon: "⚔️", price: 120, actions: [{ id: "buy", label: "Buy", icon: "💰" }] },
    ]},
  ],
  footer: [{ label: "Your gold: 250", icon: "💰" }],
});

chat.appTrigger("ClosePanel", "shop:blacksmith");

Windows reuse the HUD section types. Item actions fire app:panel_action with { action, item, section, panel }. Opening with an existing id replaces that window.

Popups

Splash

A transient banner that fades in, holds, and fades out. Several queue up and play in order.

chat.appTrigger("Splash", {
  text: "Quest Complete",
  subtitle: "The Fallen Key",
  icon: "🗝️",
  sound: "audio/quest_complete.mp3",  // optional scenario audio asset
  duration: 4,                         // seconds, 1-30
});

Notice

Dims the scene until the player presses the button. The press fires app:notice_dismissed with the notice's id.

chat.appTrigger("Notice", {
  id: "letter",
  title: "A Sealed Letter",
  text: "The wax bears no crest.",
  icon: "✉️",
  button: "Continue",
});

chat.addEventListener("app:notice_dismissed", (e) => { /* e.arguments.id */ });

Choice

A modal decision. Picking an option fires app:choice with the choice's id and the picked value. Yes/no is just a two-option choice.

chat.appTrigger("Choice", {
  id: "rebel_offer",
  title: "The Rebel Offer",
  text: "Do you take the coin?",
  choices: [
    { value: "accept",  label: "Take it",  icon: "🪙" },
    { value: "decline", label: "Refuse",   icon: "✋" },
  ],
});

chat.addEventListener("app:choice", (e) => {
  if (e.arguments.choice === "accept") chat.setFlag("joined_rebels");
});

Screen effects

Cinematic feedback over the whole stage. Transient effects play once; sticky ones stay until changed.

chat.appTrigger("ScreenEffect", { type: "flash", color: "#e5484d", edges: true, intensity: 0.6 });
chat.appTrigger("ScreenEffect", { type: "shake", intensity: 0.6 });
chat.appTrigger("ScreenEffect", { type: "glow",  color: "#3ad19b", intensity: 0.5 });
chat.appTrigger("ScreenEffect", { type: "blur",  intensity: 0.6 });
chat.appTrigger("ScreenEffect", { type: "fade",  color: "#000000", direction: "through" });
TypeEffect
flashHard colored bloom. edges: true blooms from the screen edges (damage).
glowSoft warm bloom from the center (heal).
shakeDecaying camera shake.
blurQuick defocus pulse (exertion).
fadeEase to or from a color. direction: out holds on it, in clears from it, through dips and returns.
vignetteSticky colored edge vignette. Supports pulse.
tintSticky full-screen tint. Supports pulse.
dazeSticky woozy blur.

Sticky effects clear with intensity: 0, or all at once with ClearScreenEffects.

Combat feedback

// A number that pops and drifts up. x/y are stage percentages, default over the character.
chat.appTrigger("FloatingText", { text: "-20", color: "#e5484d", size: "large" });
chat.appTrigger("FloatingText", { text: "+20", icon: "❤️", color: "#3ad19b" });

// An expanding ring burst at a point.
chat.appTrigger("Impact", { x: 50, y: 42, color: "#e5484d", intensity: 0.8 });

size is a number in rem, or small / medium / large / crit.

Character effects

Effects on a character sprite, as opposed to the whole screen. Target with name or characterId; omit both to hit everyone on screen.

chat.appTrigger("CharacterEffect", { type: "hit",    color: "#ff3b3b" });   // damage: flash + recoil
chat.appTrigger("CharacterEffect", { type: "flash",  color: "#ffffff" });
chat.appTrigger("CharacterEffect", { type: "glow",   color: "#3ad19b" });   // heal / buff
chat.appTrigger("CharacterEffect", { type: "shake" });                       // fear / cold / stun
chat.appTrigger("CharacterEffect", { type: "bounce" });                      // happy / jump
chat.appTrigger("CharacterEffect", { type: "tint", color: "#46a758", intensity: 0.5 }); // sticky

HitCharacter is shorthand for CharacterEffect with type: "hit".

Split the two perspectives: the character on screen taking a hit is a CharacterEffect; the player taking a hit is a ScreenEffect.

What's next

On this page