Semantic timeline

Present a roll journal with explosions, rerolls, drops, classifications, and progress callbacks.

This article documents the published v2. For the current physics preview, see the v3 guide. V3 ↗ Licenses ↗

displayTimeline() receives an already resolved journal. Each entry in dice defines identity, sides, and theme; faces come from roll and reroll events. View validates the whole journal before clearing the scene.

const result = await viewer.displayTimeline({
  id: 'explosion-1',
  mode: 'physics',
  dice: [
    { id: 'root', sides: 6 },
    { id: 'child', sides: 6 }
  ],
  events: [
    { sequence: 1, type: 'roll', subject: 'die', dieId: 'root', parentDieId: null, rollIndex: 1, sourceNodeId: 'n1', value: 6 },
    { sequence: 2, type: 'roll', subject: 'die', dieId: 'child', parentDieId: 'root', rollIndex: 1, sourceNodeId: 'n1', value: 4 },
    { sequence: 3, type: 'explode', subject: 'die', dieId: 'root', parentDieId: null, rollIndex: 1, sourceNodeId: 'n1', childDieId: 'child', value: 4, reason: 'explode' }
  ]
})

console.log(result.eventCount, result.phaseCount, result.degraded)

Event types

All events have a strictly increasing positive sequence, dieId, parentDieId, rollIndex, and sourceNodeId; subject may be 'die'.

type Specific fields Presentation
roll value Reveals the first face
reroll from, to, reason Changes the face; reason is reroll, reroll-once, unique, or unique-once
explode childDieId, value, reason Introduces a child; reason is explode, compound, or penetrate
transform from, to, reason Semantic adjustment; reason is minimum, maximum, penetrate, or compound
include contribution Includes a contribution
exclude reason Marks a drop; reason is drop, keep, or compound-absorbed
classify outcome Highlights success, failure, neutral, critical-success, or critical-failure

Validation covers IDs, references, initial rolls, lineage, cycles, and transitions. Do not invent a timeline from final values without rebuilding these relationships. Keep Core’s dice and matching events together.

compound and penetrate can yield values with no matching physical face. View keeps a valid face and shows the adjustment as a badge; it never invents a new face. minimum and maximum update state without their own choreography.

Configurable effects

await viewer.updateOptions({
  timeline: {
    maxDurationMs: 16_000,
    effects: {
      explode: { origin: 'source', burstHeight: 1.6, spread: 0.8 },
      reroll: { style: 'hop', hopHeight: 2.2 },
      criticalSuccess: { pulses: 2 },
      compound: { showBadge: true }
    }
  }
})

Every effect accepts enabled, delayMs, durationMs, intensity (0..1), and color. Effects include explode, compound, penetrate, reroll, unique, keep, drop, success, failure, neutral, criticalSuccess, and criticalFailure. reroll/unique offer hop, edge, or spin; explode offers source or edge; critical effects offer pulses; compound/penetrate offer showBadge. updateOptions() merges each effect deeply.

timeline.enabled defaults to true; maxEvents to 500, maxDurationMs to 12000, and phaseGapMs to 180. If disabled or over budget, View presents the final flat state and returns degraded: true. Turning off an effect changes choreography only, never the face or outcome.

Synchronize UI and scene

const viewer = new DiceResultViewer({
  container: '#dice-stage',
  onTimelineProgress(progress) {
    renderSubtotal(progress.dice)
    console.log(progress.stage, progress.completedEventSequences)
  }
})

The immutable snapshot reports stage (initial, phase, complete), phaseIndex, phaseCount, phaseId, effect, revealedDieIds, visible { id, value, discarded } dice, and completed event sequences. In physics, an explosion child may be released as soon as its parent settles, before other dice in that phase. Degraded flat playback emits only initial and complete. Callback errors are isolated.

displayTimeline() returns dice, durationMs, eventCount, phaseCount, and degraded. Unlike display(), it propagates graphical, asset, and physics failures so partial playback cannot count as success.