# How nice it is to talk — BeeDialogue lands in BeeEngine 2.11.0

> Source: <https://dev.to/antonioprosperi2svg/how-nice-it-is-to-talk-beedialogue-lands-in-beeengine-2110-cad>
> Published: 2026-11-01 11:03:43+00:00

Hi. I'm Antonio. I'm 53. I build things out of pure passion.

I don't talk much. But when I do… **BeeDialogue** comes out.

BeeEngine is a small 2D HTML5 Canvas engine I keep shaping in the open. Physics, scenes, sprites, tiles, audio buses, an inventory plugin, a locale plugin. Useful pieces. Quiet pieces.

What was missing for story-shaped games was obvious: a place for NPCs to say something without me inventing a new `if` tree every weekend.

So **v2.11.0** adds **BeeDialogue**.

Not a chatbot. Not a voice synthesizer. A dialogue *tree*: speakers, lines, branching choices, straight-line advances. The kind of thing you wire to a blue rectangle that pretends to be a guide on a bridge.

BeeEngine has a plugin contract I take seriously. The core does not import plugins. A plugin attaches itself.

``` js
import { BeeEngine } from 'beeengine';
import { BeeDialogue, BeeLocale } from 'beeengine/plugins';

const game = new BeeEngine('c', 800, 480);
const locale = new BeeLocale({ /* strings… */, engine: game });

const dialogue = new BeeDialogue({ engine: game, locale, cancelKey: 'Escape' });
// attach() registers it as 'dialogue' — detach() unregisters
```

No monkey-patch of `loop()`. No hijacking of `update` / `render`. BeeDialogue has **no tick of its own** and no DOM listeners. Your scene calls the verbs:

`handleInput(input)` from `scene.update`
`draw(ctx)` from `scene.draw` (screen space, after the camera)
The motor stays a motor. The plugin stays a plugin. I sleep better.

You `load` a tree once. Nodes can be an array (easier to skim) or a map. Literal `text` / `speaker` work. Or `textKey` / `speakerKey` if you pass an optional **BeeLocale** (constructor, `setLocale`, or `engine.plugin('locale')`).

```
dialogue.load({
  start: 'intro',
  nodes: [
    {
      id: 'intro',
      speakerKey: 'guide',
      textKey: 'hi',
      choices: [
        { textKey: 'ask_map', next: 'map', data: { topic: 'map' } },
        { textKey: 'bye', next: null, data: { topic: 'bye' } }
      ]
    },
    { id: 'map', speakerKey: 'guide', textKey: 'map', next: 'tip' },
    { id: 'tip', speakerKey: 'guide', textKey: 'tip' }
  ]
});
```

Rules that saved me from myself:

`choices` → `advance()` follows `next` (or ends).`choose(index)`.` false` and warns. Good. I need warnings more than cleverness.`start()` while already open does a clean restart (`end` with reason `restart`, then `start` again).
BeeDialogue is not `BeeText.drawHUD`. It draws a simple panel when you ask.

``` js
const scene = {
  update(_dt, input) {
    if (input.wasPressed('KeyE') && !dialogue.isOpen()) dialogue.start();
    dialogue.handleInput(input); // Space / Enter advances or confirms; arrows move the highlight
  },
  draw(ctx) {
    dialogue.draw(ctx, { x: 40, width: ctx.canvas.width - 80 });
  }
};
```

`onChange` reports `start`, `node`, `choice`, `advance`, and `end` (with a `reason`: `finished`, `cancel`, `restart`, `reload`, `missing-node`…). Enough to feed a future quest plugin without hard-wiring anything today.

And yes — `toJSON` / `fromJSON` save the tree and where you stood, so you can tuck the DTO into `BeeSave` next to inventory slots. Definitions stay yours; restore reopens on the saved node and emits `node` (not a fake second `start`).

The demo is `examples/dialogue.html`. Press **E**.

The English string does **not** say “E to talk”.

It says **“E to interact”**.

Because BeeDialogue does not talk. It does not clear its throat. It does not do regional accents. It advances nodes. The joke writes itself, and I left it in the locale table on purpose (`talk: 'E to interact'`). Press **L** if you want Italian. The guide still will not speak aloud. She will, however, mention a village east of a bridge, which is already more social than most of my week.

I like small contracts:

| Piece | Job | 
|---|---|
| BeeLocale | `t(key)` — pure read | 
| BeeInventory | stacks, use, equip — no draw loop | 
| BeeDialogue | tree state — you draw and feed input | 

Together they feel like a tiny RPG toolkit without pretending to be one. Next ideas on the shelf (one at a time): Quest, Post FX, scene Transition, action remapping… Lights, Spine, Net later. Those touch more surface area. Dialogue was the polite guest who hangs its coat on `attach` and leaves with `detach`.

`beeengine` `examples/dialogue.html`
`node scripts/test-beedialogue.mjs`
`import { BeeDialogue } from 'beeengine/plugins'`
If you break it, tell me how. If you use it in a jam game with three lines of dialogue and a torch tip, tell me that too. Short messages welcome — I don't talk much.

But when I do… you already know what comes out.

— Antonio
