DicExWeb.DiceRoller (dicEx v0.3.0)

Copy Markdown View Source

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 (see DicEx.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) or true. By default the server's roll is always the result: the 3D dice tumble physically and settle on the faces Elixir chose. With physics={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 (default nil ⇒ DicEx.RNG.Default). Pass DicEx.RNG.Entropy for cryptographic, non-replayable randomness.
  • limits — keyword list of parse limits passed to DicEx.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 (default 6000).
  • on_roll — a pid, registered name, {name, node}, {:global, name} or {:via, module, name} to notify of every roll via send/2 with {: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