Updating the view every few ms


I’m going through the Elm guide, and working through https://guide.elm-lang.org/effects/random.html. I’m stuck on trying one of the expansion ideas at the bottom:

  • Have the dice flip around randomly before they settle on a final value.

One thought I had to do this was to:

  1. add a tumbleCount to the model
    type alias Model = { tumbleCount : TumbleCount , rolls : DiceValues }
  2. add a Tumble message:
    type Msg = Roll | Tumble DiceValues | Landed DiceValues
    type alias DiceValues = List Int
  3. set tumbleCount to e.g. 10 when the Roll message is received in update
  4. decrement the tumbleCount, and settle on a DiceValues when it hits zero

This makes update look like:

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        Roll ->
                -- User clicked roll button, start tumbling
            ( { model | tumbleCount = 10 }
            , Random.generate Tumble rolls

        Tumble newRolls ->
                c =
                    (log "tumbleCount" model).tumbleCount
            if c == 0 then
                -- Finished tumbling
                ( model
                , Random.generate Landed rolls

                -- Tumbling continues
                ( { model | tumbleCount = model.tumbleCount - 1, rolls = newRolls }
                , Random.generate Tumble rolls

        Landed newRolls ->
            ( { model | rolls = newRolls }
            , Cmd.none

The problem is that only the last Landed msg causes the dice view to update. Judging from the log calls, the right stuff is happening to the model, but either they are happening too fast to cause visible updates to the die faces, or, since they are chained too quickly, the Tumble updates are getting collapsed (and ignored) so that the view is not updated. Is that what’s happening?

All of which is to say (if I haven’t XY problemed this problem already): I want to update the view every 200ms or so while the dice are tumbling. How can I do that?


this intuition is correct. You burn through those 10 rolls in about 160 ms which is too little to notice visually.

To solve this you need to introduce some time into your rolls. You can do this either by using Browser.Events.onAnimationFrameDelta and an accumulator that you use to trigger the next tumble OR you can use Process.sleep and sleep few hundred milliseconds between tumbles.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.