Voxta docs

Stage Editor

Visual-novel-style scene editor — place clickable buttons over a background image, style them, attach scripts, and watch your scenario come to life.

The Stage Editor is a dedicated visual editor for building visual-novel-style scenarios in Voxta. You set a background image, drop clickable buttons on top of it, style them however you want, and attach scripts that fire when the user clicks. Voxta renders the result in the stage view at chat time.

This is the editor behind scenarios like Okay View Residence — where the player navigates a building by clicking doors painted onto a hallway image, and each door knock fires a script that swaps the background, enables a character, and plays a sound.

The Stage Editor builds on top of regular events — each button is an event with Button timing. The editor is the visual front-end for authoring those events. You can edit the same fields in the regular event editor, but the Stage Editor gives you a live canvas to position, style, and preview them.

How to open it

In the Scenario Editor:

  1. Set the scenario's default view to Stage in App Configuration.
  2. Set a background image (App Configuration → Background).
  3. Go to the Events tab.
  4. Create or open an event with Button timing.
  5. Click the full-screen / position button on the event row.

The Stage Editor opens as a full-screen overlay with your background as the canvas.

What's on screen

RegionWhat it does
CanvasYour scenario background. The button you're editing is drawn at its current position. Other Button-timing events appear as semi-transparent "ghosts" for reference.
Bottom toolbarToggle grid, snap-to-grid, chat-UI overlay preview, config panel, navigation panel. Save / Exit.
Config panel (draggable)The five tabs that drive the event — General, Position, Style, Scripts, Assets.
Nav panel (draggable, optional)A list of every Button event in the scenario for quick switching.

The config and nav panels are draggable — move them out of the way of whatever you're working on.

The five tabs

General

Event metadata — name, description, flag filter, "once" toggle, set-flags list, the Note injected when the event fires. Same fields as the regular event row, just laid out for the visual editor.

Position

Where the button sits on the background.

  • Absolute positioning — drag the button on the canvas. Coordinates are stored as percentages so the layout survives resolution changes.
  • Snap to grid — quantize movement.
  • Distort mode — the button has four draggable corner points for perspective distortion. Use this to make a button conform to a door, a TV screen, or any non-rectangular surface in the background.

When distort mode is on, the four corners (btn_p0btn_p3) control the shape. When off, the button is a regular rectangle sized by btn_width / btn_height.

Style

This is where most of the design work happens. The Style tab is a full button constructor with:

Presets

Pick a preset to start from, then tweak. Seven presets ship:

PresetLook
0. Voxta DefaultNeutral dark button with subtle shadow.
1. Cyberpunk NeonBold cyan-on-black with neon glow + monospace font.
2. Smooth GradientPill-shaped pink-to-orange gradient.
3. Danger / CriticalStripes background, red border, Impact font.
4. GlassmorphismTranslucent white with backdrop blur.
5. Retro 3D GameHard 3D shadow, yellow / black, pixel font.
6. Minimal GhostOutline-only, faint text, handwritten font.

Fonts

System, Monospace, Serif, Impact, Handwritten, Retro Pixel.

Fill types

  • Solid Colorbtn_bg only.
  • Linear Gradientbtn_bgbtn_bg_2, angle controlled by btn_gradient_angle.
  • Stripes — striped pattern using both colors.

Shadow styles

  • None — no shadow.
  • Soft — drop shadow.
  • Retro 3D — hard offset shadow (no blur).
  • Neon Glow — colored glow around the button.
  • Border Glow (Hover) — glow only when hovered.

Text shadow

None, Soft, Hard (Retro), Neon — independent of the button shadow.

Image background

Drop in an asset and the button becomes a hot-clickable image instead of a styled rectangle. Image fit options: Cover, Contain, Stretch (Fill). Combine with btn_text_visible: false to make image-only buttons (e.g. a clickable door painted on the background).

Other knobs

Border color/width/opacity, background opacity, text color/opacity, corner radius, letter spacing, scale, backdrop blur, font weight, italics, uppercase text, hover effects.

Copy / paste styles

Copy the style of one button and paste it onto another to keep a consistent look across a scenario.

Scripts

The JavaScript that runs when the user clicks. This is a regular scripting block — the same import { chat } from "@voxta" editor as everywhere else, with full access to flags, role enablement, app triggers, queued operations, and so on.

Typical click handler patterns:

import { chat } from "@voxta";

export function trigger(e) {
  // Swap the background to a new room
  chat.appTrigger('SetBackground',
    chat.scenario.assets.get("backgrounds/lobby.png"));

  // Disable all tenants, enable just the lobby one
  const roles = ["main", "role2", "role3", "role4", "role5", "role6", "role7"];
  for (const role of roles) {
    chat.queue.roleEnabled(role, false);
  }
  chat.queue.roleEnabled("role3", true);

  // Move the scenario state via slotted flags
  chat.queue.setFlags("context_slot_places.lobby", "button_lobby");
}

Assets

Quick-browse the scenario's asset folder to pick images, sounds, music for use in the button's image background or in its click script. Same picker as elsewhere in the editor.

Authoring patterns

Visual navigation between locations

Pattern: use slotted flags as the current location, and one button per destination.

// Each "go to backyard" button:
chat.setFlags("!places", "button_lobby", "context_slot_places.backyard");
chat.appTrigger("SetBackground", chat.scenario.assets.get("backgrounds/backyard.png"));

Then declare contexts gated on those flags so the AI knows where the user is:

Context name: place_backyard
FlagsFilter: context_slot_places.backyard
Text: {{ user }} is standing in the backyard of the building, with picnic tables...

See Flags → Enum flags for how the context_slot_places.* dot-syntax works.

Knock + door open + room reveal

A common pattern from Okay View Residence: clicking a door plays a knock sound, maybe opens the door (probabilistic), and on open, queues a background change, an ambient track, a tenant enable, and a context flag — all timed to land after the knock sound finishes.

import { chat } from "@voxta";

const knockSounds = [
  chat.scenario.assets.get('SFX/Knock_1.mp3'),
  chat.scenario.assets.get('SFX/Knock_2.mp3'),
  chat.scenario.assets.get('SFX/DoorBell.mp3')
];
const doorOpenSound = chat.scenario.assets.get('SFX/DoorOpening.mp3');

export function trigger(e) {
  // 1. Immediate: random knock sound
  const knock = knockSounds[Math.floor(Math.random() * knockSounds.length)];
  chat.appTrigger('PlaySound', knock, 100);

  // 2. 33% chance the door opens
  if (Math.random() < 0.33) {
    // Queued: each of these waits for the previous audio to finish
    chat.queue.appTrigger('PlaySound', doorOpenSound, 100);
    chat.queue.appTrigger('SetBackground',
      chat.scenario.assets.get("backgrounds/room_tenant.png"));
    chat.queue.roleEnabled("tenant_role", true);
    chat.queue.roleMessage('tenant_role', '');
    chat.queue.setFlags("context_slot_places.tenant_room", "button_leave_apt");
  }
}

chat.queue.* operations wait their turn in the message queue, so the door-opening sound plays after the knock, and the room background swaps after the door sound. See App triggers → Queued vs immediate.

Image-only buttons painted onto the scene

Set btn_image_url, hide the text (btn_text_visible: false), and the button becomes a transparent click target with whatever artwork you provide. Common for door clickable areas, signs, NPC silhouettes, etc.

For more complex shapes that aren't rectangles, turn on distort mode and drag the four corners to match the perspective of the background.

Stage view at chat time

When the user is in stage view, the chat renders:

  • The current background asset (set via App Configuration or SetBackground).
  • Every Button-timing event whose FlagsFilter is satisfied — buttons that don't match their filter are hidden.

This is what lets you change which buttons are visible by setting flags. A button visible only in the lobby has FlagsFilter: context_slot_places.lobby; once the user moves elsewhere, the flag changes, and the button disappears.

See also

On this page