← All demos
The indie studioBudget: A small studio’s sprintSix people, a year
The Rusty Anchor
Marta keeps her drowned husband's anchor over the bar. Finn is the only man who came back from that ship. Pip is a bard who has noticed more than she says. Walk in, talk to them, spill a drink, and watch each of them answer the same moment from a different history.
Click Look around (drag to look if the pointer will not lock)WASD WalkE Talk to the person you are facing
What this game actually sends
- PersonaHow they talk. Authored once.
- BackstoryWho they are because of what happened. Authored once.
- SituationWhat is going on around them right now. Sent by the game.
- EventThe thing that just happened. This is what they react to.
import { npc } from '@npc/client';
// Three characters, one key. Backstories live on the server.
const marta = npc({ key: 'pk_live_…', id: 'marta' });
const finn = npc({ key: 'pk_live_…', id: 'finn' });
// Each one gets its own view of the same room.
marta.setSituation('Night. A storm is rolling in. You are wiping the bar. A stranger is at the bar.');
finn.setSituation('Night. You are slumped over your mug at the corner table. Marta is behind the bar.');
// Thunder hits, and every character answers it in their own way.
const [m, f] = await Promise.all([
marta.react('A crack of thunder rattles the shutters.'),
finn.react('A crack of thunder shakes the whole tavern.'),
]);
playAnimation(marta, m.behaviour); // e.g. 'go_quiet'
playAnimation(finn, f.behaviour); // e.g. 'flinch'
// Free text goes through say(); actions are checked against a policy.
const r = await marta.say('An ale, please.');
if (r.action?.name === 'serve_drink') pourDrink(r.action.args);The panel on the right is the real trace of those calls, not a mock-up. Characters here are cast from 8 demo NPCs across three games. Read the docs →