A self-contained LiveComponent that renders the pixel-art 3D dice roller.
Drop it into any LiveView (inline or as a modal) and it manages its own state:
the current expression, the quick dice tray, and the last roll result. The 3D
animation is driven by the DiceRoller JavaScript hook which lives in
priv/static/dic_ex.min.js.
Usage
# in your LiveView template (inline)
<.live_component module={DicExWeb.DiceRoller} id="dice-roller" />
# as a modal — wrap it however you like
<.modal :if={@show_roller}>
<.live_component module={DicExWeb.DiceRoller} id="dice-roller" />
</.modal>Options
default— initial expression (default"1d20"). Only applied when it changes, so parent re-renders never wipe what the player typed.theme—"obsidian"(default),"arcane"or"dnd", or a custom palette map (seeDicEx.Theme).engine—"3d"(default; Three.js + Rapier physics) or"2d"(canvas, no physics: the die tumbles in 2D and lands on the authoritative value).physics—false(default) ortrue. By default the server's roll is always the result: the 3D dice tumble physically and settle on the faces Elixir chose. Withphysics={true}the 3D engine becomes physics-is-truth: the faces that land are reported back and become the result. The client decides that outcome, so only use it where cheating does not matter. It only applies to pools of d4/d6/d8/d10/d12/d20 without explode or reroll; other rolls stay server-authoritative.rng— RNG module or{module, state}for the rolls (defaultnil⇒DicEx.RNG.Default). PassDicEx.RNG.Entropyfor cryptographic, non-replayable randomness.limits— keyword list of parse limits passed toDicEx.roll_e/2(:max_dice,:max_sides,:max_length).labels— map overriding the UI strings::add,:clear,:roll,:rolling,:placeholder,:input. Defaults are English.reveal_timeout— milliseconds before the result is revealed even if the dice never report settling (default6000).on_roll— apid, registered name,{name, node},{:global, name}or{:via, module, name}to notify of every roll viasend/2with{:dic_ex_rolled, %{result: result, component: id}}.
Receiving rolls
<.live_component module={DicExWeb.DiceRoller} id="roller"
on_roll={self()} />
def handle_info({:dic_ex_rolled, %{result: result}}, socket) do
# result is a %DicEx.Result{}; feed its JSON map to the LLM
{:noreply, socket}
end