Skip to content

Room tables

A room table is a page like a sheet, with two differences:

  • there is one per room, and it stays open for everyone, as a tab;
  • only game masters write; players see it.

They are for what belongs to the room, not to a character: the campaign’s NPCs, a calendar, the travel map, the factions’ reputation.

In the manifest, replace "sheets" with "tables":

"tables": [{ "type": "com.yourname.system.npcs", "title": "NPCs" }]

A single .html file brings one sheet or one table. A package can bring both, with one HTML for each.

  1. Install the plugin in Room settings → Plugins.
  2. In the … tables group, below the plugin, click Enable.
  3. The table opens for everyone as a tab that doesn’t come into view, next to the other tables (or in the last space used): click its name to see it.

Disabling it closes the table for everyone and keeps the data: enabling it again brings everything back as it was.

  • kind is 'table', and item.ownerId is null (the table has no owner).
  • The manifest’s private does not apply to tables: hide parts with doc.restrict (see Private parts).
  • The game master’s controls get data-role="gm": for players, the fields already lock by themselves, but the create and delete buttons disappear.
  • To change a player’s card, say whose: RPGDesk.card.setBar(0, 7, 12, { userId }), with the id from await RPGDesk.room.players().
Room NPCsDownload the .htmlOpen in a new tab ↗

Test mode: the data stays in this browser only. The band in the corner switches the role (GM, sheet owner, another player) and shows the log of rolls.

The example is a list where each NPC has a name, HP, initiative, notes and a button to roll initiative, all with HTML attributes. The JavaScript does two things:

RPGDesk.connect().then(({ doc, me }) => {
const npcs = doc.list('npcs');
const empty = document.getElementById('empty');
// "No NPCs yet." disappears when the list has items
npcs.watch((items) => { empty.hidden = items.length > 0; }, { now: true });
if (me.role !== 'gm') return;
// "Hidden from players": the NPC becomes game master only
const seen = new Map();
npcs.watch((items, { local }) => {
for (const npc of items) {
const hidden = npc.hidden === true;
if (seen.get(npc.id) === hidden) continue;
seen.set(npc.id, hidden);
if (local) doc.restrict(['npcs', '#' + npc.id], hidden ? 'gm' : null);
}
}, { now: true });
});
  • Only the browser of the game master who checked the box (local) calls restrict: the other game masters with the table open do not repeat the request.
  • The hidden NPC really disappears for players: the server does not even send it.