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.
| /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. |
/r./R, /Gr, /LR, /BR,
dFUDGE, Db6 all work.
| 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 |
Expressions support +, -, *, /, and parentheses.
Math functions are powered by mathjs. Common helpers that work out of the box:
| /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. |
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 |
/r max (db6 + 1d4)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. |
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.
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). |
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.
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" });
/r, /gr, /lr, /liarroll, /br,
/blindroll, /say, max, min, etc.false for silent / background rolls.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);
}
});
{
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
}
}
{
callId: string,
expressionIn: string,
ok: true,
data: {
isSay: true,
message: string
}
}
{
callId: string,
expressionIn: string,
ok: false,
error: "PARSE_ERROR" | "ROLL_ERROR" | string
}
| 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. |
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}`);
}
}
);
Need help, found a bug, or want to suggest an improvement? Choose whichever channel works best for you.
@citron3400
Join server
GitHub Issues
Report a reproducible bug or request a feature.
Open an issue