Skip to content

Client interface

The client runtime translates authoritative server messages into calls on an interface adapter. Start with the bundled adapter, configure it, or implement the adapter contract yourself.

Client

Bundled interface

The simplest client bootstrap creates and owns a DefaultAdapter:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local MrDialogue = require(ReplicatedStorage.Packages.MrDialogue)

local runtime = MrDialogue.Start()

The bundled interface:

  • Reveals text by grapheme, preserving UTF-8 and RichText.
  • Adds a pause after common punctuation.
  • Supports mouse, keyboard, touch buttons, and gamepad selection.
  • Lets number keys 1 through 9 select visible choices.
  • Freezes character movement by default and restores its previous values.
  • Animates the dialogue and choice panels.

Configure the default adapter

Create it explicitly and pass it to Start:

local adapter = MrDialogue.DefaultAdapter.new({
    charsPerSecond = 45,
    punctuationPause = 0.1,
    freezeCharacter = false,
})

local runtime = MrDialogue.Start({
    adapter = adapter,
})
Option Type Default Description
gui ScreenGui? Bundled GUI Existing interface to use
charsPerSecond number? 30 Positive reveal speed
punctuationPause number? 0.15 Additional non-negative pause
freezeCharacter boolean? true Adapter fallback for movement freezing

When DialogueDefinition.freezeCharacter is present, it overrides the adapter fallback for that session.

Ownership of supplied adapters

MrDialogue.Stop() destroys only the default adapter that Start() created internally. If you supply an adapter, you own it and should call Destroy() when it is no longer needed.

Use a custom ScreenGui

The default adapter accepts an existing GUI, but its descendants must follow this contract:

DialogueGui (ScreenGui)
├── DialogueFrame (GuiObject)
│   ├── ContinueButton (GuiButton)
│   ├── NpcIcon (ImageLabel)
│   ├── NpcName (TextLabel)
│   └── DialogueLabel (ScrollingFrame)
│       └── TextLabel (TextLabel)
└── OptionsFrame (GuiObject)
    └── OptionsFrame (ScrollingFrame)
        └── OptionTemplate (GuiButton)

If OptionTemplate is an ImageButton, it must contain a TextLabel. The adapter clones the template for every available option.

local gui = game.Players.LocalPlayer.PlayerGui:WaitForChild("DialogueGui")

local adapter = MrDialogue.DefaultAdapter.new({
    gui = gui,
})

MrDialogue.Start({ adapter = adapter })

Implement a custom adapter

A custom adapter implements six methods:

local adapter = {}

function adapter:OnShow(info)
    -- Open the interface.
end

function adapter:OnPresentation(presentation, actions)
    -- Render presentation.text, then acknowledge it.
    actions.presentationCompleted()
end

function adapter:OnAdvanceReady(actions)
    -- Bind the next user input to actions.advance().
end

function adapter:OnFinishReady(actions)
    -- Bind the final user input to actions.finish().
end

function adapter:OnChoices(options, actions)
    -- Render options and call actions.choose(index).
end

function adapter:OnEnd(outcome)
    -- Close the interface and clear local state.
end

MrDialogue.Start({ adapter = adapter })

Do not retain an action callback after the corresponding UI state is replaced. The runtime ignores stale callbacks, but the adapter should still disconnect obsolete buttons and animations.

Presentation data

OnPresentation receives:

{
    kind = "line" | "choice_prompt",
    speaker = {
        name = "Guide",
        icon = "rbxassetid://123",
    }?,
    text = "Where are you going?",
}

OnChoices receives an array containing only:

{
    { text = "The market." },
    { text = "The castle." },
}

The client never receives option IDs, targets, or conditions.

Cancel or stop

MrDialogue.CancelActiveSession()

Requests authoritative cancellation and leaves the runtime available for another session.

MrDialogue.Stop()

Stops the runtime, disconnects networking, and cancels any active session. If an active custom adapter receives OnEnd during shutdown, the outcome has authoritative = false because the client cannot wait for the server reply.