JustDices

A formula-based dice roller for Owlbear Rodeo — fast, flexible, and API-friendly. Type natural formulas, click a button, or call the broadcast API from other extensions.

Commands

/r <expr>
/roll <expr>
Public roll broadcast to the whole room. Examples: /r d20   /roll 2d6+3   /r max 10d20
/gr <expr>
/gmroll <expr>
Hidden roll — visible to the GM and the roller only. Examples: /gr db6   /gmroll (2dF + 1)
/lr <expr>
/liarroll <expr>
Liar roll — logged for the whole room, with the result initially visible only to the roller. Examples: /lr d20   /liarroll 2d6+3
/br <expr>
/blindroll <expr>
Blind roll — logged for the whole room, with the result initially visible only to GMs. Examples: /br d20   /blindroll 2d6+3
/say <message> Send a text message to the chat (also callable via API). Example: /say The beast roars!
/help Display a quick command reference card inside JustDices.
No prefix? JustDices treats the input as a public roll — same as /r.
Commands are case-insensitive: /R, /Gr, /LR, /BR, dFUDGE, Db6 all work.

Formula Language

Core dice notation

Syntax Description Example
NdX Roll N dice with X faces. N is optional (defaults to 1). 2d6, d20, D20
NdX! Exploding dice — reroll when the max face is rolled. 4d6!
NdX!>=T Exploding dice with a custom threshold T. 4d6!>=5
NdXkY Roll N dice, keep the highest Y. 4d6k3
NdXdY Roll N dice, drop the lowest Y. 4d6d1
NdF / NdFudge Fudge/Fate dice — result in {−1, 0, +1}. Defaults to 4 dice. 4dF, 2dFudge
NdbX Pokemon Tabletop United Damage Base — expands to a full dice+bonus expression. db6, 2db4

Arithmetic & math functions

Expressions support +, -, *, /, and parentheses.

Math functions are powered by mathjs. Common helpers that work out of the box:

sqrt   abs   ceil   floor   round   min   max   log   exp   sin   cos   tan   …
⚠️ Functions are evaluated by mathjs. Unknown names will throw a parse error.

Practical examples

/r 2d6 + 3 Two d6 plus a flat +3.
/r (1d8 + 2) * 2 Roll 1d8, add 2, double the result.
/r 4d6k3 Classic D&D stat roll — keep best 3 of 4d6.
/r 4dF + 2 Fate/Fudge roll with a +2 modifier.
/r sqrt(25) + 1d6 Math function combined with a die roll.
/gr db6 + 1d4 Hidden Pokemon Tabletop United Damage Base roll with bonus die.

Prefixes & Modifiers

Place max or min before the expression to force every die to its maximum or minimum value. Useful for testing or theoretical maximums.

Prefix Effect Example
max <expr> Every die shows its maximum face. /r max 10d20 → [20, 20, …]
min <expr> Every die shows its minimum face (1). /r min db6 → all internal d6 roll 1
Always place the prefix before the expression: /r max (db6 + 1d4)

Pokemon Tabletop United Damage Base (db)

Implements the Pokemon Tabletop United 1.05 Damage Base table. dbX expands to its full dice + flat bonus expression (e.g. db6 → 2d6+8). The table covers db1 through db28.

db6 Standard crit-less Damage Base roll.
2db4 Multiplied DB (e.g. for criticals).
db6 + 1d4 - 2 Mixed DB with regular dice and flat modifiers.

Buttons

⚔️ Roll it Sends /r <expr> — public roll with whatever is typed in the input field.
🙈 Hidden roll Sends /gr <expr> — GM-only roll with the current input.
🎲 Quick Rolls Toggles the Quick Rolls panel (see below).
If the formula already starts with an opposite prefix (e.g. you type /gr … and press ⚔️), the UI will warn you.

Quick Rolls

The Quick Rolls panel provides a grid of the most common dice. Click the number of dice you want to roll and the expression is sent automatically — just like typing it manually.

The 🐵 / 🙈 toggle inside the panel switches between public and hidden rolls for the quick-click buttons.

Roll History

Every roll produces a card in the Rolls History pane. Cards are prepended (most recent on top) and cleared on reload — nothing is persisted.

Expression display The typed expression is shown on the card. Hover 🔍 to reveal the expanded expression (e.g. db6 → (2d6+8)).
Per-die coloring Min face values are shown in red, max face values in green.
Critical animations All-max results trigger a green glow animation; all-min trigger a red glow.
Hidden rolls 🔒 Only the rolling player and GMs can see hidden roll cards.
Liar rolls 🤥 Everyone sees that a roll happened, but only the roller sees its result initially. The roller or a GM can click 👁️ to reveal it to everyone.
Blind rolls 🙈 Everyone sees that a roll happened, but only GMs see its result initially. The roller or a GM can click 👁️ to reveal it to everyone.
🎲 Reroll button Replays the exact original expression — preserves whether the roll is public, hidden, liar, or blind.
↑ / ↓ keys Navigate command history directly in the input field (up to 50 entries).

Broadcast API

JustDices exposes an OBR broadcast API that lets any other Owlbear extension trigger a roll and receive a structured response. No UI interaction is required.

Request

Send a message on channel com.sewef.justdices/api.request:

// Channel: "com.sewef.justdices/api.request"
OBR.broadcast.sendMessage("com.sewef.justdices/api.request", {
  callId:      "my-unique-id-123",  // string — correlates request ↔ response
  expression: "/r 2d6+3",         // string — same syntax as the input box
  showInLogs: true               // boolean (default true) — also push to log
}, { destination: "LOCAL" });

Parameters

callIdrequired
A unique string identifier for this call. Used to correlate the request with its response when you listen on the response channel.
expressionrequired
The formula or full command string. All command prefixes are accepted: /r, /gr, /lr, /liarroll, /br, /blindroll, /say, max, min, etc.
showInLogsoptional · default: true
Whether to also display the result in the JustDices roll log. Set to false for silent / background rolls.

Listening for the response

Filter by your callId on channel com.sewef.justdices/api.response:

OBR.broadcast.onMessage("com.sewef.justdices/api.response", (evt) => {
  const res = evt.data;
  if (res.callId !== myCallId) return;

  if (res.ok) {
    console.log("Total:",    res.data.total);
    console.log("Expanded:", res.expressionOut);
    console.log("Detail:",   res.rolls);  // HTML string with colored dice
  } else {
    console.warn("Roll failed:", res.error);
  }
});

Response structure

Roll — ok: true

{
  callId:        string,
  expressionIn:  string,  // what you sent
  ok:            true,
  expressionOut: string,  // expanded display
  rolls:         string,  // HTML, colored dice
  data: {
    expression:  string,
    rolls:       string,
    total:       number,
    allDiceMin:  boolean,
    allDiceMax:  boolean
  }
}

Say — ok: true

{
  callId:       string,
  expressionIn: string,
  ok:           true,
  data: {
    isSay:    true,
    message: string
  }
}




Error — ok: false

{
  callId:       string,
  expressionIn: string,
  ok:           false,
  error:        "PARSE_ERROR" | "ROLL_ERROR" | string
}

Error codes

PARSE_ERROR The expression has invalid syntax or unsupported tokens. The roll was not executed.
ROLL_ERROR The expression parsed correctly but the internal evaluation failed.
API_TIMEOUT Client-side: no response received before your own timeout. JustDices may not be running.

Complete example

const callId = crypto.randomUUID();

OBR.broadcast.sendMessage("com.sewef.justdices/api.request", {
  callId,
  expression: "/r 4d6k3",
  showInLogs: false
}, { destination: "LOCAL" });

const unsub = OBR.broadcast.onMessage(
  "com.sewef.justdices/api.response",
  (evt) => {
    const res = evt.data;
    if (res.callId !== callId) return;
    unsub(); // unsubscribe after receiving our response

    if (res.ok) {
      console.log(`Rolled: ${res.expressionOut} = ${res.data.total}`);
    }
  }
);

Contact

Need help, found a bug, or want to suggest an improvement? Choose whichever channel works best for you.