Dialogue Box

NPC dialogue panel with a continue prompt.

▶ Run in browser

Tags: ui dialogue game-ui

What it demonstrates

  • A panel anchored across the bottom of the screen with AnchorPreset.BOTTOM_WIDE.

  • Speaker name + body text driven by a list of dialogue lines.

  • A “continue” button that advances through the lines and closes on the last one.

  • Top-level Controls use anchors + margins, never absolute position.

Run: uv run python examples/features/ui/dialog.py

Source

  1"""Dialogue Box: NPC dialogue panel with a continue prompt.
  2
  3# /// simvx
  4# tags = ["ui", "dialogue", "game-ui"]
  5# web = { root = "DialogueDemo", width = 800, height = 600, responsive = true }
  6# ///
  7
  8## What it demonstrates
  9- A panel anchored across the bottom of the screen with `AnchorPreset.BOTTOM_WIDE`.
 10- Speaker name + body text driven by a list of dialogue lines.
 11- A "continue" button that advances through the lines and closes on the last one.
 12- Top-level Controls use anchors + margins, never absolute position.
 13
 14Run: uv run python examples/features/ui/dialog.py
 15"""
 16
 17from simvx.core import AnchorPreset, Colour, Label, Node, Panel, Vec2
 18from simvx.core.ui import Button
 19from simvx.graphics import App
 20
 21# A short scripted conversation: (speaker, line).
 22LINES = [
 23    ("Guide", "Welcome to the village, traveller."),
 24    ("Guide", "The old mine to the north has been overrun."),
 25    ("Guide", "Take this lantern. You will need its light."),
 26    ("Guide", "Good luck out there. Come back safe."),
 27]
 28
 29
 30class DialogueDemo(Node):
 31    """Root node: a bottom-anchored NPC dialogue box."""
 32
 33    def on_ready(self):
 34        self._index = 0
 35
 36        # Bottom-anchored dialogue panel: full width, fixed height at the
 37        # bottom edge. Margins inset it slightly from the screen edges.
 38        panel = Panel(name="DialoguePanel")
 39        panel.set_anchor_preset(AnchorPreset.BOTTOM_WIDE)
 40        panel.margin_left = 20
 41        panel.margin_right = -20
 42        panel.margin_top = -180
 43        panel.margin_bottom = -20
 44        panel.bg_colour = Colour.hex("#15171F")
 45        self.add_child(panel)
 46
 47        # Speaker name, top-left inside the panel.
 48        self._speaker = Label(name="Speaker")
 49        self._speaker.font_size = 18.0
 50        self._speaker.text_colour = Colour.hex("#FFCC66")
 51        self._speaker.set_anchor_preset(AnchorPreset.TOP_WIDE)
 52        self._speaker.margin_left = 20
 53        self._speaker.margin_right = -20
 54        self._speaker.margin_top = 14
 55        self._speaker.size_y = 24
 56        panel.add_child(self._speaker)
 57
 58        # Body text, fills the remaining panel area.
 59        self._body = Label(name="Body")
 60        self._body.font_size = 15.0
 61        self._body.text_colour = Colour.LIGHT_GRAY
 62        self._body.set_anchor_preset(AnchorPreset.FULL_RECT)
 63        self._body.margin_left = 20
 64        self._body.margin_right = -20
 65        self._body.margin_top = 48
 66        self._body.margin_bottom = -56
 67        panel.add_child(self._body)
 68
 69        # Continue button, bottom-right of the panel.
 70        self._continue = Button("Continue", on_press=self._advance)
 71        self._continue.set_anchor_preset(AnchorPreset.BOTTOM_RIGHT)
 72        self._continue.size = Vec2(140, 32)
 73        self._continue.margin_left = -160
 74        self._continue.margin_top = -44
 75        self._continue.margin_right = -20
 76        self._continue.margin_bottom = -12
 77        panel.add_child(self._continue)
 78
 79        self._panel = panel
 80        self._show_current()
 81
 82    def _show_current(self):
 83        """Render the dialogue line at the current index."""
 84        speaker, text = LINES[self._index]
 85        self._speaker.text = speaker
 86        self._body.text = text
 87        last = self._index == len(LINES) - 1
 88        self._continue.text = "Close" if last else "Continue"
 89
 90    def _advance(self):
 91        """Move to the next line, or close the box on the last line."""
 92        if self._index >= len(LINES) - 1:
 93            self._panel.visible = False
 94            return
 95        self._index += 1
 96        self._show_current()
 97
 98
 99if __name__ == "__main__":
100    App(title="SimVX Dialogue Box", width=800, height=600).run(DialogueDemo())