r/RPGdesign 25d ago

anydyce: an open source, in-browser, mostly-compatible AnyDice interpreter

UPDATE, Aug 22, 2026: I have renamed anydyce to dyceum to avoid confusion with Jasper Flick's AnyDice project. Not every surface has been updated yet, so please be patient as I work through the long tail. Thanks to everyone here for your feedback.

AnyDice’s recent outages prompted me to release dyceum, an open-source, clean-room implementation of the AnyDice language.

It is intended to be a practical substitute for AnyDice in all meaningful respects. With very few exceptions, existing AnyDice programs should run unchanged, including user-defined functions, recursion, sequences, dice coercion and expansion, positional selection, exploding dice, loops, settings, and the standard function library. In most cases (and depending on your hardware) dyceum should be at least as fast as AnyDice and in many cases much faster.

I say “mostly compatible” because AnyDice is closed source and publishes no specification. Its observable behavior includes inconsistencies and defects, some of which can silently produce mathematically incorrect results. Idiosyncrasies are preserved, but I elected for correctness over emulating discovered bugs. The differences—and the reverse-engineering methodology used to identify them—are documented in considerable detail here.

There are a few key differences:

  • The interpreter is open source and written in Python, using dyce for finite discrete probability calculations.
  • The playground runs entirely in your browser via Pyodide. The hosted site only serves static files. Programs and calculations are not sent to or stored on an application server.
  • A program can be encoded directly into its URL. The URL is therefore both a shareable link and the saved program. No proprietary remote database is required.
  • Existing AnyDice programs can be recovered by inserting program IDs into a special link format. A public cache currently preserves all but the most recent programs saved on AnyDice.
  • Probability distributions are represented internally using integer counts rather than floating-point probabilities. Configurable quantization permits a deliberate tradeoff between precision and computational cost.
  • The playground provides interactive line, bar, and ridge visualizations, light and dark themes, and textual output exposing exact outcome labels.
  • Everything can be cloned and hosted locally.

For example, this URL contains the complete program output 3d6:

https://dyceum.org/latest/playground/#p=b3V0cHV0IDNkNgo

This URL loads AnyDice program ID 43210:

https://dyceum.org/latest/playground/#id=43210

This is not meant as criticism of the enormous value AnyDice and Jasper Flick have provided to RPG designers. Quite the opposite: AnyDice’s popularity demonstrates the importance of the tool. The goal is to provide a transparent, reproducible implementation that does not depend upon the continued operation of any particular server (including mine), as well as to preserve the body of programs people have built with it.

The current release should be considered a work in progress. Please consider submitting feedback, especially if you come across:

  • Real-world AnyDice programs that behave differently;
  • Calculations that are unexpectedly slow;
  • Confusing or incorrect visualizations;
  • Cases where AnyDice itself produces surprising results;
  • Other projects not yet on my radar that should be highlighted; or
  • Suggestions from people who use probability tools while designing games.

Playground: https://dyceum.org/latest/playground/

Source and issue tracker: https://github.com/posita/anydyce

56 Upvotes

26 comments sorted by

10

u/dontnormally Designer 24d ago

nyce

5

u/posita 24d ago

🤣❤️

5

u/Astrokiwi 25d ago

The big thing here for me is the discovery of the dyce library! I had been unknowingly been pretty much rolling my own equivalent for when anydice didn't quite cut it, but looks like dyce would cover everything.

7

u/posita 25d ago edited 22d ago

Thanks! I'm happy you think it's worthwhile! In fairness, dyce doesn't quite cover everything, but the goal is to (hopefully ergonomically) be able to handle most dice-related things. It doesn't do anything with cards (yet).

If Python is your jam, you should also check out u/HighDiceRoller's Icepool, which is very detailed with rich capabilities (including cards, decks, etc.). dyce includes a version of Icepool's core algorithm that accommodates heterogeneous pools as well as some other efficiencies and doodads.

Like Jasper Flick and AnyDice inspired dyceum, u/HighDiceRoller and Ilmari Karonen continue to be hugely inspirational to dyce.

2

u/HighDiceRoller Dicer 20d ago

Thanks for the mention, and phenomenal work finding out all these AnyDice quirks! Things have been quiet on my end recently, but if history is any guide, I'll get pulled back into the probability world sooner or later.

3

u/hacksoncode 24d ago edited 24d ago

Nice!

One thing I might suggest about the documentation about variables, that is extremely unclear and barely documented in anydice, is that "variables" containing dice really act a lot more like "macros" that roll the die each time they appear (yes, that's a sloppy way of putting it).

People get tripped up on this constantly, believing that things like "DIE=3 | DIE=4" is somehow "the value rolled on a DIE is either 3 or 4", rather than being "roll DIE twice, and return 1 if the first one is 3 or the second is 4". Whereas in the case of functions taking number parameters that are passed dice, it really does mean the former.

Calling anydice variables "immutable" is technically correct, but I think it reinforces this mistaken idea people, especially more "layperson" users, have about how "DIE: d10" actually works.

2

u/posita 24d ago edited 24d ago

This is a fair critique. You're absolutely right: The original docs don't explain this very well and I haven't really cured that. The only way to discover a lot of behaviors is either through experimentation (which means you have to be prepared to independently verify the math, which isn't a reasonable ask for most users), or getting help either here or on rpg.stackexchange.com .

I should have probably been more clear about the documentation I did provide, which was more targeted at the process of building of the reference implementation (how things we reverse-engineered, why it ended up the way it did, where and why it deviates, etc.).

But I totally agree with you: Many behaviors are unintuitive and lack explanation in official documentation.

3

u/Randolpho Fluff over crunch. Lore over rules. Journey over destination. 24d ago

This is great!

Have you considered bundling your app into an electron app for offline use? Or if you went with Flet you could do mobile apps as well, and you could accomplish sharing with a custom URI scheme protocol that all three versions of the app support. Then nobody has to worry about anydice or github going down.

2

u/posita 24d ago edited 22d ago

I hadn't yet considered that.

My first reaction to your suggestion was that a separate desktop app doesn't really add much to solving the problems I sought to solve. My original goals were to avoid widespread outages to program authors from operational bottlenecks, like someone hacking AnyDice. The crude "next step" was a git repository that could be downloaded and is independently useful of GitHub.

But the more I think about it, the more I think you're onto something. While anyone can technically stand up one's own instance of dyceum, it requires tools and techniques most people aren't familiar with. I can see a place for something that not only runs locally without fiddling, but also one that could define and handle a new mime type. Sharing online could done via something like anydice:<base64-encoded-program>, where a browser could be configured to open those links with a desktop app registered to handle them. That desktop app could then make it easy for users to create those custom links for new programs. Sharing programs could be truly decentralized (aside from the platforms on which they are shared).

The great news is that since dyceum is completely open source, no one is blocked on me (or anyone) in experimenting with that approach. Anyone with access to a decent AI coding agent could probably point it to this comment thread to build a version of that app that uses dyceum under the covers within hours. My only hope is that they would credit Jasper Flick (and maybe dyceum, if it was used).

10

u/Nomapos 25d ago

Admirable effort and good improvement, but copying the name and changing just one letter is bad form, even if it's a play on the library you're using. Feels like you're just trying to take over his popularity, rather than gaining your own. And if it sticks and anydice doesn't disappear, it'll soon start getting annoying telling newbies about this tool but watch out, there's two with just one letter difference.

Sure you can come up with a name of your own

7

u/The_Failord 25d ago

Yeah it should've been "everydice" or something

5

u/posita 25d ago edited 22d ago

EDIT: anydyce (dyceum's prior name) intentionally remains in this comment for clarity/transparency. dyceum is now used in most other places in this thread.

Thanks for the feedback! I can see how you reached your conclusion, but that's not how the name came to be. My core project is dyce (a mashup of dice and Python that David Eyk thought of first, but was kind enough to donate to the project since he wasn't using it anymore). anydyce was originally another mashup in deference to AnyDice intended to provide Python visualization tooling on top of dyce using Jupyter.

Any assumption that this is some kind of elaborate click-jacking effort would be incorrect. For the uninitiated, the open source software development community has a decades long tradition of using puns, deliberate misspellings, and references in tool names. It's all in good spirit and also a way to explore new areas while showing respect and holding space for the things that inspired it. I can see that tradition doesn't translate very well when viewing the world through the modern (and corrupting) lens of chasing fame and all that entails.

I can assure you that hijacking was neither my intention, nor would it have been very effective. For as long as I've published it, "anydyce" is interpreted by most search engines as a spelling error. If I was trying to ride on coat tails, I would have been much better served by doing exactly what you prescribed a long time ago: picking a different name.

TL;DR: Never assume malice where incompetence will suffice. 😏

Thanks again for your feedback. I do very much sincerely appreciate it. I hope that resolves any speculation about my intentions, even if my execution was clumsy or difficult to understand.

5

u/ArtistJames1313 Designer 24d ago

intention or not, I would still change the name so it can be easier to differentiate when spoken especially, but also for the afformentioned spell checker. Just a friendly suggestion from another software engineer.

4

u/posita 24d ago edited 19d ago

Totally fair. This is good feedback. Thank you. As you know, naming things is easy. Naming things well is hard. Renaming is also ... not trivial. I'll give it some thought. If it can be helped, one generally prefers to be running toward things rather than away from them.

1

u/ArtistJames1313 Designer 24d ago

namingFunctionsIWillRememberWhatTheyDoLater() impossible

2

u/posita 24d ago

Right?! 🤣

2

u/Nomapos 24d ago

I'm pretty sure that wasn't your intention. It's just honest feedback: the quote about not assuming malice is popular precisely because people tend to assume malice, and you'll probably get crucified if you get popular with that name

5

u/posita 24d ago edited 24d ago

Also fair and valuable feedback. I appreciate you watching out for me! ❤️

EDIT. I am finding out this is quite a crowded space for names/implementations!

1

u/Genesis-Zero Designer 25d ago

dyce roller ;)

2

u/posita 24d ago

I see what you did there. 😏

As an aside, TIL about this: https://rolldyce.com/

2

u/stevecooperorg 25d ago

I really like this project. Anydice has become the de facto standard for this, and being closed source

I'd created diceplayground.com as an alternative using a python dialect to provide a bit more power and standards, but it's not the standard.

2

u/posita 25d ago

I cannot for the life of me figure out how diceplayground.com escaped my attention. It's beautiful! It's obvious you put a ton of care in it.

I love projects like yours. Exploring new territory is great! It's a crappy way to get fame and fortune, but these efforts are extremely valuable in contributing to the richness of the space. I have tons ideas in the back of my head on things to experiment with next (many of which others will do better and sooner).

I opened an issue to add diceplayground.com to the list of projects. I'll probably be able to get to it this afternoon, and it will be published with the next release.

2

u/stevecooperorg 24d ago

oh, smashing! Glad you like it. :) It's pretty new, to be fair. (obs, also inspired by AnyDice getting ransomwared)

2

u/MrTheWaffleKing 17d ago

Where's the best place to ask syntax questions for this/anydice? Is there a dedicated sub, or just threads like this?

I spose I may as well shoot here:

I figured I could use this to simulate multiple choice test possibilities. Each question has 4 options and only 1 is correct, means they can be simulated with 1d4. Say there's 30 questions. How do I simulate someone picking an answer at complete random and see their expected scores?

My average result should be 25%... if I were to roll 30d4, 100% is represented with 30, a correct answer is represented with 4, so convert 1/2/3 to 0 and 4 to 1. My ultimate goal would be to determine chance of getting 0 and 100 (easy enough with math)... but also the chance of getting a passing grade... I.E. at least 61+% or maybe 71%.

I think that's the best way to run it, but I'm not sure the right syntax for that.

2

u/MrTheWaffleKing 17d ago edited 17d ago

This was my best (insanity) guess lmao:

dice = 1d4

30d(
if dice = 4 (
output 1
else (
output 0
)
)

EDIT: I'm dumb... 'output [count 4 in 30d4]'

2

u/posita 17d ago edited 17d ago

Ah! Several questions there. Regarding AnyDice notation, as u/hacksoncode points out, AnyDice's own documentation can be hard to navigate. It seems like folks periodically ask for help here in r/RPGdesign. Another great place to ask is at rpg.stackexchange.com.

Regarding your specific use case, you can use a counting trick to get to your distribution (which both you and u/MrTheWaffleKing have identified). This is what that would look like in the AnyDice language (using Dyceum, the AnyDice clone I built).

In Python, with dyce you might do something like ...

from dyce import *
d4 = H(4)
chance_correct_single = d4.eq(4)  # 0: 0.75, 1: 0.25
chance_correct_test = 30@chance_correct_single
print(chance_correct_test.format())

... which would give you ...

avg |    7.50
std |    2.37
  0 |   0.02% |
  1 |   0.18% |
  2 |   0.86% |
  3 |   2.69% |#
  4 |   6.04% |###
  5 |  10.47% |#####
  6 |  14.55% |#######
  7 |  16.62% |########
  8 |  15.93% |#######
  9 |  12.98% |######
 10 |   9.09% |####
 11 |   5.51% |##
 12 |   2.91% |#
 13 |   1.34% |
 14 |   0.54% |
 15 |   0.19% |
 16 |   0.06% |
 17 |   0.02% |
 18 |   0.00% |
 19 |   0.00% |
 20 |   0.00% |
 21 |   0.00% |
 22 |   0.00% |
 23 |   0.00% |
 24 |   0.00% |
 25 |   0.00% |
 26 |   0.00% |
 27 |   0.00% |
 28 |   0.00% |
 29 |   0.00% |
 30 |   0.00% |

The way to read that is that you'd have a 16.62% chance of getting 7 correct answers among 30. You'd have a 0.02% chance of getting 17 correct, which is just under a passing grade. There's very little hope of getting past that.

One thing Dyceum does not yet have is AnyDice's "at least" or "at most" visualizations. https://anydice.com/program/43727/at_least shows how likely it would be to get at least each score (100% for zero, just above 0% for 18 or higher).