miso
Copyright(C) 2016-2026 David M. Johnson
LicenseBSD3-style (see the file LICENSE)
MaintainerDavid M. Johnson <code@dmj.io>
Stabilityexperimental
Portabilitynon-portable
Safe HaskellNone
LanguageHaskell2010

Miso.Subscription.RAF

Description

Overview

Miso.Subscription.RAF provides rAFSub, a subscription that hooks into the browser's requestAnimationFrame loop. On each frame the browser calls back with a DOMHighResTimeStamp (milliseconds since page load, sub-millisecond precision), which is forwarded to the component as an action.

This is the recommended driver for canvas-based animations and games because the browser throttles the callback to the display refresh rate (typically 60 fps) and pauses it automatically when the tab is hidden.

Quick start

import Miso
import Miso.Subscription.RAF
import Miso.Canvas

data Action = Tick Double   -- DOMHighResTimeStamp in ms

myComponent = (component model update view)
  { subs   = [ rAFSub Tick ]
  , events = defaultEvents
  }

update :: Action -> Effect p props Model Action
update (Tick t) = do
  modify (\m -> m { time = t })

Lifecycle

Internally rAFSub uses createSub:

  • Acquire — schedules the first requestAnimationFrame callback, which re-schedules itself on every invocation.
  • Release — calls freeFunction to cancel the callback and release the JS reference when the component unmounts.

See also

Synopsis

Documentation

rAFSub Source #

Arguments

:: (Double -> action)

Callback fired each frame with a DOMHighResTimeStamp in milliseconds

-> Sub action 

A Sub for 60FPS animations when using requestAnimationFrame.

The Double returned is a DOMHighResTimeStamp expressed in milliseconds.

rAFSubElapsed Source #

Arguments

:: Double

Minimum interval between ticks in milliseconds (e.g. 175 for ~6 fps)

-> action

Action to dispatch each time the interval elapses

-> Sub action 

Like rAFSub but fires action at most once per interval milliseconds.

Elapsed time is accumulated in IORefs inside the subscription so the model is not touched between ticks — Miso only re-renders when a tick actually fires, rather than on every animation frame.

app = defaultApp model update view
  { subs = [ rAFSubElapsed 175 Tick ] }