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