DEV Community

Cover image for How nice it is to talk — BeeDialogue lands in BeeEngine 2.11.0
Antonio
Antonio

Posted on

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

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.


From “dialogue” to a dialogue plugin

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.


The engine stays blind (on purpose)

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

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
Enter fullscreen mode Exit fullscreen mode

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.


A tree you can read

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' }
  ]
});
Enter fullscreen mode Exit fullscreen mode

Rules that saved me from myself:

  • Node without choices → advance() follows next (or ends).
  • Node with choices → choose(index).
  • The wrong verb returns 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).

Drawing choices (without becoming a second renderer)

BeeDialogue is not BeeText.drawHUD. It draws a simple panel when you ask.

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 });
  }
};
Enter fullscreen mode Exit fullscreen mode

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).


About that demo label

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.


Why this shape

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.


Try it

  • Repo: BeeEngine-V2.5.0 (package beeengine 2.11.0)
  • Demo: examples/dialogue.html
  • Tests: node scripts/test-beedialogue.mjs
  • Import: 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

Top comments (0)