Roll a set of ability scores
4d6kh3 — throw four six-sided dice, keep the highest three — is the most common way to roll
a character’s ability scores, and a set is six of them. This guide rolls the set in one
request and shows the working for each.
Rollful knows the notation and nothing about the game. What a score means, how many you need and what you do with them are yours; this guide only rolls the dice.
Roll one score
Section titled “Roll one score”import { roll } from 'opendice'
const score = roll('4d6kh3')
score.total // 14curl 'https://api.rollful.dev/v1/roll?formula=4d6kh3'Roll all six in one request
Section titled “Roll all six in one request”Over HTTP, send them as a batch rather than six separate calls. One round trip instead of six, and the whole set is counted against a single dice budget — 24 dice, well inside it.
curl -X POST https://api.rollful.dev/v1/roll/batch \ -H 'content-type: application/json' \ -d '{"rolls":[ {"formula":"4d6kh3"},{"formula":"4d6kh3"},{"formula":"4d6kh3"}, {"formula":"4d6kh3"},{"formula":"4d6kh3"},{"formula":"4d6kh3"} ]}'The response is { "rolls": [...] } with one result per roll, in the order you sent
them. There is no identifier to match on, so keep your own order.
const response = await fetch('https://api.rollful.dev/v1/roll/batch', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ rolls: Array.from({ length: 6 }, () => ({ formula: '4d6kh3' })) }),})
const { rolls } = await response.json()
rolls.map((score) => score.total) // [14, 12, 16, 9, 13, 11]In the package there is no batch to make — call roll() six times.
const scores = Array.from({ length: 6 }, () => roll('4d6kh3'))Show which die was dropped
Section titled “Show which die was dropped”Each result carries the four dice it threw, so a set can be printed with its working intact.
const line = (score) => { const group = score.dice[0] const shown = group.results.map((die, i) => (group.keptFlags[i] ? `${die}` : `(${die})`))
return `${shown.join(' ')} = ${score.total}`}
rolls.map(line)// [ '5 4 5 (3) = 14', '6 (1) 3 3 = 12', ... ]In the package, keptFlags is a function rather than a field — keptFlags(group). See
Show the working in a UI for the rendering in full.
Vary the set
Section titled “Vary the set”The formula is the only thing that changes if your table rolls differently.
| Formula | What it does |
|---|---|
4d6kh3 |
four dice, keep the highest three |
4d6kl3 |
four dice, keep the lowest three |
3d6 |
three dice, straight |
2d6+6 |
three to twelve, plus six |
5d6kh3 |
five dice, keep the highest three |
Rerolling ones, dropping the lowest score of the set, or a floor on the total are rules rather than notation. Do them in your own code, on the results the API returns — every die is there to decide with.
Where to go next
Section titled “Where to go next”- Show the working in a UI — rendering these properly.
- Survive the limits — what happens when a batch gets large.
- The formula grammar — everything else a formula can say.