Voxta docs

Flags

State bits that filter actions and contexts, settable from actions, events, and scripts.

Flags are named booleans that track the current state of a chat. Simple strings: is_thirsty, wears_hat, door_closed. You set them from actions, events, or scripts; you read them from conditions on actions and contexts.

A character with the flag wears_hat set will:

  • Have the wear_hat action filtered out (it's a no-op — they already wear it).
  • Have the {{ char }} is wearing a hat context render in every prompt.

That's the core loop. Everything else is variations.

Setting and unsetting

A flag is set by including its name. Prefix with ! to unset:

wears_hat           # set
!wears_hat          # unset

You can do both in the same effect — e.g. an action that takes off a hat and reveals a hairstyle might set !wears_hat, ponytail_visible.

Enum flags (mutually exclusive)

Some flags are mutually exclusive — a character can be standing OR sitting OR dancing, but not all three. Manually unsetting "all the other poses" every time you change is tedious. Voxta solves this with dot-syntax enum flags:

pose.standing
pose.sitting
pose.dancing

Setting pose.dancing automatically unsets pose.standing and pose.sitting. The pose. prefix means "all flags starting with pose. are mutually exclusive."

Unsetting enums

  • !pose.standing — unsets only pose.standing. Other pose.* flags untouched.
  • !pose — unsets all pose.* flags. Useful for resetting a category.

Flag conditions

Conditions are mini JS-like boolean expressions used on actions and contexts.

ExpressionMeaning
pose.standingActive only if pose.standing is set.
!pose.standingActive only if pose.standing is NOT set.
pose.standing && !door.closedBoth must hold.
hold.empty_bottle || hold.empty_glassEither holds.
(a || b) && !cUse parens to group.

Setting from a script

import { chat } from "@voxta";

export function trigger(e) {
  // Set a flag
  chat.setFlag('wears_hat');

  // Unset
  chat.unsetFlag('wears_hat');
  // Equivalent:
  chat.setFlag('!wears_hat');

  // Enum
  chat.setFlag('pose.sitting');  // auto-clears pose.standing etc.

  // Multiple at once
  chat.setFlags('wears_hat', 'pose.standing', '!is_drenched');

  // Check
  if (chat.hasFlag('wears_hat')) { /* ... */ }
}

See Scripting for the full chat-state API.

Expiring flags

Set a flag that auto-clears after a duration:

// Expires after 10 conversation messages
chat.setFlag('cooldown', { messages: 10 });

// Expires after 2 minutes of chat time
chat.setFlag('cooldown', { seconds: 120 });

Useful for cooldowns, "just happened" markers, and short-lived emotional states.

Patterns

Once-ever events

Use the Once checkbox on an action — Voxta auto-generates an invisible _action_name flag and an !_action_name condition. Fires once per chat.

State machines

Use enum flags for state machines. state.intro, state.investigation, state.confrontation — only one is set at a time, and transitions are explicit.

Location / slot navigation

A specialization of state machines, common in visual-novel and stage-view scenarios. Use a single enum flag as the "current location" and gate every context, action, and button on it:

Flag set:      context_slot_places.lobby      (or .backyard, .corridor, etc.)
Context:       "{{ user }} is standing in the lobby..."     FlagsFilter: context_slot_places.lobby
Button:        "Go to backyard"                              FlagsFilter: context_slot_places.lobby
                — fires: setFlags("context_slot_places.backyard", ...)

Setting context_slot_places.backyard auto-clears context_slot_places.lobby, the lobby context disappears, the lobby buttons hide, the backyard context appears, the backyard buttons show. One flag, one source of truth for where the user is. See the Stage Editor for the visual side of this pattern.

Looping events

Set a flag from an event, then use since flag <flag> on the same event with a message-count delta. The event fires, sets its own flag, re-arms, fires again.

What's next

On this page