WAAPI Engine¶
This page is a practical guide to using the WAAPI engine. Read Engines Overview when you want side-by-side comparisons and tradeoffs.
The WAAPI Engine uses the Web Animations API via Elm ports and a JavaScript companion. It combines browser-native performance with programmatic control.
Example¶
3D animation - rotating cube with expanding sides.
View Example
View Source Code
port module Animation.WAAPI.Animate3D.Main exposing (main)
import Anim.Builder exposing (AnimBuilder, ForWAAPI)
import Anim.Engine.WAAPI as WAAPI
import Anim.Extra.View3D as View3D
import Anim.Property.Rotate as Rotate
import Anim.Property.Translate as Translate
import Anim.Unit exposing (Unit(..))
import Browser exposing (Document)
import Html exposing (Html, div, text)
import Html.Attributes exposing (id, style)
import Json.Encode as Encode
import Motion.Easing as Easing exposing (Easing(..))
import Process
import Task
-- PORTS
port motionCmd : Encode.Value -> Cmd msg
port motionMsg : (Encode.Value -> msg) -> Sub msg
-- MAIN
main : Program () Model Msg
main =
Browser.document
{ init = \_ -> init
, view = view
, update = update
, subscriptions = subscriptions
}
-- MODEL
type alias Model =
{ animState : WAAPI.AnimState Msg
, state : State
}
init : ( Model, Cmd Msg )
init =
let
initialAnimState =
WAAPI.init motionCmd motionMsg <|
[ -- Bring the cube forward on the Z axis
-- so that it doesn't get clipped by the
-- z=0 clipping plane when we expand the
-- sides and rotate. This is a fixed 3D depth
-- offset, unrelated to layout, so it stays
-- in pixels.
Translate.initZ cubeGroupName 200 >> Translate.cssUnit Px
-- Position each face in 3D space along the axis it faces.
-- Face offsets use `Cqmin` so the cube scales proportionally
-- with the stage's new dimensions on resize.
-- Front/Back faces move on Z (forward/backward)
-- Left/Right faces move on X (sideways)
-- Top/Bottom faces move on Y (up/down)
, Translate.initZ frontFace.groupName depth >> Translate.cssUnit Cqmin
, Translate.initZ backFace.groupName (depth * -1)
>> Translate.cssUnit Cqmin
-- Rotate each face into position to build the cube
-- Front face is not rotated due to facing forward by default
>> Rotate.initY backFace.groupName 180
, Translate.initX rightFace.groupName depth
>> Translate.cssUnit Cqmin
>> Rotate.initY rightFace.groupName 90
, Translate.initX leftFace.groupName (-1 * depth)
>> Translate.cssUnit Cqmin
>> Rotate.initY leftFace.groupName -90
, Translate.initY topFace.groupName (-1 * depth)
>> Translate.cssUnit Cqmin
>> Rotate.initX topFace.groupName 90
, Translate.initY bottomFace.groupName depth
>> Translate.cssUnit Cqmin
>> Rotate.initX bottomFace.groupName -90
-- The text labels all start on the same plane as their faces
-- at z=0, which is the default starting value, so we don't need
-- to initialize them
]
in
( { animState = initialAnimState
, state = Opening
}
, Process.sleep 0
|> Task.perform (always TriggerAnimation)
)
type State
= Opening
| Closing
| RotatingOpen
| RotatingClosed
-- Cube configuration
cubeGroupName : String
cubeGroupName =
"cubeAnim"
{-| Cube edge length expressed in `Cqmin` (% of the stage's smaller
dimension). The stage applies `container-type: size`, so the cube
resizes automatically with the viewport without any Elm-side
measurement.
-}
cubeSize : Float
cubeSize =
18
cubeSizeCss : String
cubeSizeCss =
String.fromFloat cubeSize ++ "cqmin"
{-| Distance each face sits in front of / behind the cube centre.
Half the cube edge so adjacent faces meet at the cube corners.
-}
depth : Float
depth =
cubeSize / 2
-- Face configuration
type alias TextConfig =
{ id : String
, groupName : String
, label : String
, color : String
}
type alias FaceConfig =
{ id : String
, groupName : String
, label : String
, background : String
, borderColor : String
, text : TextConfig
}
frontFace : FaceConfig
frontFace =
{ id = "front-face"
, groupName = "frontFaceAnim"
, label = "FRONT"
, background = "rgb(52, 152, 219)"
, borderColor = "rgb(41, 128, 185)"
, text =
{ id = "front-face-text"
, groupName = "frontFaceTextAnim"
, label = "FRONT"
, color = "rgb(0,0,0)"
}
}
backFace : FaceConfig
backFace =
{ id = "back-face"
, groupName = "backFaceAnim"
, label = "BACK"
, background = "rgb(41, 128, 185)"
, borderColor = "rgb(33, 97, 140)"
, text =
{ id = "back-face-text"
, groupName = "backFaceTextAnim"
, label = "BACK"
, color = "rgb(0,0,0)"
}
}
rightFace : FaceConfig
rightFace =
{ id = "right-face"
, groupName = "rightFaceAnim"
, label = "RIGHT"
, background = "rgb(231, 76, 60)"
, borderColor = "rgb(192, 57, 43)"
, text =
{ id = "right-face-text"
, groupName = "rightFaceTextAnim"
, label = "RIGHT"
, color = "rgb(0,0,0)"
}
}
leftFace : FaceConfig
leftFace =
{ id = "left-face"
, groupName = "leftFaceAnim"
, label = "LEFT"
, background = "rgb(230, 126, 34)"
, borderColor = "rgb(211, 84, 0)"
, text =
{ id = "left-face-text"
, groupName = "leftFaceTextAnim"
, label = "LEFT"
, color = "rgb(0,0,0)"
}
}
topFace : FaceConfig
topFace =
{ id = "top-face"
, groupName = "topFaceAnim"
, label = "TOP"
, background = "rgb(46, 204, 113)"
, borderColor = "rgb(39, 174, 96)"
, text =
{ id = "top-face-text"
, groupName = "topFaceTextAnim"
, label = "TOP"
, color = "rgb(0,0,0)"
}
}
bottomFace : FaceConfig
bottomFace =
{ id = "bottom-face"
, groupName = "bottomFaceAnim"
, label = "BOTTOM"
, background = "rgb(155, 89, 182)"
, borderColor = "rgb(142, 68, 173)"
, text =
{ id = "bottom-face-text"
, groupName = "bottomFaceTextAnim"
, label = "BOTTOM"
, color = "rgb(0,0,0)"
}
}
-- ANIMATIONS
--
-- CUBE
--
-- We only rotate the cube, not individual faces, they maintain their
-- position in 3D space because we use `View3D.transformStyle View3D.Preserve3D`
-- on the cube container
rotateCube : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
rotateCube to =
WAAPI.for cubeGroupName
>> Rotate.begin
>> Rotate.toXYZ to to to
>> Rotate.easing BackInOut
>> Rotate.duration 8000
>> Rotate.end
rotateCubeClockwise : WAAPI.EngineBuilder -> WAAPI.EngineBuilder
rotateCubeClockwise =
rotateCube 360
rotateCubeAntiClockwise : WAAPI.EngineBuilder -> WAAPI.EngineBuilder
rotateCubeAntiClockwise =
rotateCube 0
-- SIDES
moveSidesOut : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveSidesOut targetAmount =
moveFrontFaceOut targetAmount
>> moveBackFaceOut targetAmount
>> moveRightFaceOut targetAmount
>> moveLeftFaceOut targetAmount
>> moveTopFaceOut targetAmount
>> moveBottomFaceOut targetAmount
moveSidesIn : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveSidesIn targetAmount =
moveFrontFaceIn targetAmount
>> moveBackFaceIn targetAmount
>> moveRightFaceIn targetAmount
>> moveLeftFaceIn targetAmount
>> moveTopFaceIn targetAmount
>> moveBottomFaceIn targetAmount
sharedTiming : WAAPI.EngineBuilder -> WAAPI.EngineBuilder
sharedTiming =
WAAPI.duration 1000
>> WAAPI.easing CircInOut
moveFace : FaceConfig -> (Translate.Builder ForWAAPI -> Translate.Builder ForWAAPI) -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveFace config moveToBuilder =
sharedTiming
>> WAAPI.for config.groupName
>> Translate.begin
>> moveToBuilder
>> Translate.end
-- Each face moves along the axis it faces by a `moveAmount` (expressed in
-- `Cqmin`, so it scales with the stage) when the cube expands, and moves
-- back to its original position when the cube closes.
--
-- Front/Back faces move on Z (forward/backward)
-- Left/Right faces move on X (sideways)
-- Top/Bottom faces move on Y (up/down)
moveAmount : Float
moveAmount =
10
moveFrontFaceOut : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveFrontFaceOut toZ =
moveFace frontFace <|
Translate.toZ (toZ + moveAmount)
moveFrontFaceIn : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveFrontFaceIn toZ =
moveFace frontFace <|
Translate.toZ toZ
moveBackFaceOut : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveBackFaceOut toZ =
moveFace backFace <|
Translate.toZ (-1 * toZ - moveAmount)
moveBackFaceIn : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveBackFaceIn toZ =
moveFace backFace <|
Translate.toZ (-1 * toZ)
moveRightFaceOut : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveRightFaceOut toX =
moveFace rightFace <|
Translate.toX (toX + moveAmount)
moveRightFaceIn : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveRightFaceIn toX =
moveFace rightFace <|
Translate.toX toX
moveLeftFaceOut : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveLeftFaceOut toX =
moveFace leftFace <|
Translate.toX (-1 * toX - moveAmount)
moveLeftFaceIn : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveLeftFaceIn toX =
moveFace leftFace <|
Translate.toX (-1 * toX)
moveTopFaceOut : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveTopFaceOut toY =
moveFace topFace <|
Translate.toY (-1 * toY - moveAmount)
moveTopFaceIn : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveTopFaceIn toY =
moveFace topFace <|
Translate.toY (-1 * toY)
moveBottomFaceOut : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveBottomFaceOut toY =
moveFace bottomFace <|
Translate.toY (toY + moveAmount)
moveBottomFaceIn : Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveBottomFaceIn toY =
moveFace bottomFace <|
Translate.toY toY
-- TEXT
--
-- Text moves forward (Z+4cqmin) and rotates (to Z=360deg) when sides expand,
-- and then moves back (to Z=0cqmin) and rotates back (to Z=0deg) when sides close
textMoveAmount : Float
textMoveAmount =
14
moveText : TextConfig -> Float -> Float -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveText config toZ toRotate =
sharedTiming
>> WAAPI.for config.groupName
>> Translate.begin
>> Translate.toZ toZ
>> Translate.end
>> Rotate.begin
>> Rotate.toZ toRotate
>> Rotate.end
moveTextsOut : WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveTextsOut =
moveText frontFace.text textMoveAmount 360
>> moveText backFace.text textMoveAmount 360
>> moveText rightFace.text textMoveAmount 360
>> moveText leftFace.text textMoveAmount 360
>> moveText topFace.text textMoveAmount 360
>> moveText bottomFace.text textMoveAmount 360
moveTextsIn : WAAPI.EngineBuilder -> WAAPI.EngineBuilder
moveTextsIn =
moveText frontFace.text 0 0
>> moveText backFace.text 0 0
>> moveText rightFace.text 0 0
>> moveText leftFace.text 0 0
>> moveText topFace.text 0 0
>> moveText bottomFace.text 0 0
selectAnimation : Float -> State -> WAAPI.EngineBuilder -> WAAPI.EngineBuilder
selectAnimation targetAmount state =
case state of
Opening ->
moveSidesOut targetAmount
>> moveTextsOut
Closing ->
moveSidesIn targetAmount
>> moveTextsIn
RotatingOpen ->
rotateCubeClockwise
RotatingClosed ->
rotateCubeAntiClockwise
-- UPDATE
type Msg
= NoOp
| GotWaapiMsg WAAPI.AnimMsg
| TriggerAnimation
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
NoOp ->
( model, Cmd.none )
TriggerAnimation ->
let
( animState, cmd ) =
WAAPI.animate model.animState <|
selectAnimation depth model.state
in
( { model | animState = animState }
, cmd
)
GotWaapiMsg animMsg ->
let
( animState, maybeAnimEvent ) =
WAAPI.update animMsg model.animState
in
case maybeAnimEvent of
Just animEvent ->
handleMotionEvent animEvent { model | animState = animState }
Nothing ->
( { model | animState = animState }, Cmd.none )
handleMotionEvent : WAAPI.AnimEvent -> Model -> ( Model, Cmd Msg )
handleMotionEvent animEvent model =
case animEvent of
WAAPI.Ended "cubeAnim" ->
cubeRotationEnded model
WAAPI.Ended "frontFaceAnim" ->
sidesMovementEnded model
_ ->
( model, Cmd.none )
cubeRotationEnded : Model -> ( Model, Cmd Msg )
cubeRotationEnded model =
case model.state of
RotatingOpen ->
stateChanged Closing model
RotatingClosed ->
stateChanged Opening model
_ ->
( model, Cmd.none )
sidesMovementEnded : Model -> ( Model, Cmd Msg )
sidesMovementEnded model =
case model.state of
Opening ->
stateChanged RotatingOpen model
Closing ->
stateChanged RotatingClosed model
_ ->
( model, Cmd.none )
stateChanged : State -> Model -> ( Model, Cmd Msg )
stateChanged state model =
let
( animState, cmd ) =
WAAPI.animate model.animState <|
selectAnimation depth state
in
( { model
| state = state
, animState = animState
}
, cmd
)
-- SUBSCRIPTIONS
subscriptions : Model -> Sub Msg
subscriptions model =
WAAPI.subscriptions GotWaapiMsg model.animState
-- VIEW
view : Model -> Document Msg
view model =
{ title = "WAAPI 3D Example"
, body =
[ div
[ Html.Attributes.class "example-stage"
, id "example-stage"
, style "width" "min(90vw, 90vh)"
, style "height" "min(90vw, 90vh)"
, style "container-type" "size"
]
[ viewAnimationArea model
]
]
}
viewAnimationArea : Model -> Html Msg
viewAnimationArea model =
div
[ -- Perspective container
View3D.perspective 1000
, View3D.perspectiveOrigin View3D.Center
--
-- Hack for Chrome on macOS GPU compositing issues with 3D transforms.
-- Setting opacity: 0.99 forces a new compositing layer, which prevents
-- the colored rectangle artifacts that can appear during complex 3D animations.
-- It's not perfect, some flickering can still occur.
, View3D.opacityHack
, id "animation-area"
, style "display" "flex"
, style "justify-content" "center"
, style "align-items" "center"
, style "width" "100%"
, style "height" "100%"
, style "flex" "0 0 auto"
]
[ viewCube model ]
viewCube : Model -> Html Msg
viewCube model =
div
(WAAPI.attributes cubeGroupName model.animState
++ [ View3D.transformStyle View3D.Preserve3D
, id "cube"
, style "width" cubeSizeCss
, style "height" cubeSizeCss
, style "position" "relative"
]
)
[ viewFace model.animState frontFace
, viewFace model.animState backFace
, viewFace model.animState rightFace
, viewFace model.animState leftFace
, viewFace model.animState topFace
, viewFace model.animState bottomFace
]
viewFace : WAAPI.AnimState Msg -> FaceConfig -> Html Msg
viewFace animState config =
div
(WAAPI.attributes config.groupName animState
++ [ View3D.transformStyle View3D.Preserve3D
, id config.id
, style "position" "absolute"
, style "width" cubeSizeCss
, style "height" cubeSizeCss
, style "background-color" config.background
, style "border" ("2px solid " ++ config.borderColor)
, style "box-sizing" "border-box"
, style "display" "flex"
, style "justify-content" "center"
, style "align-items" "center"
, style "font-weight" "bold"
, style "font-size" ("calc(" ++ cubeSizeCss ++ " * 0.13)")
]
)
[ div
[ style "color" "#ffffff"
, style "position" "absolute"
]
[ text config.label ]
, div
(WAAPI.attributes config.text.groupName animState
++ [ id config.text.id
, style "color" config.text.color
, style "position" "absolute"
]
)
[ text config.text.label ]
]
Quick Walkthrough¶
Here's a general workflow to get up an running quickly.
1. Build¶
View Source Code
2. Initialize¶
Make your module a port module, define your ports: motionCmd and motionMsg, and pass them to init with your property initializers.
View Source Code
port module Main exposing (main)
import Json.Decode
import Json.Encode
-- Outgoing to JS
port motionCmd : Json.Encode.Value -> Cmd msg
-- Incoming from JS
port motionMsg : (Json.Decode.Value -> msg) -> Sub msg
type alias Model =
{ animState : WAAPI.AnimState Msg }
init : ( Model, Cmd Msg )
init =
( { animState =
WAAPI.init motionCmd motionMsg <|
[ Opacity.init "card" 0 ] }
, Cmd.none
)
3. Render¶
Render WAAPI attributes on the animated element.
View Source Code
4. Trigger with animate¶
Call animate to start a state-tracked animation.
View Source Code
5. React¶
Subscribe to events, then process messages with update.
View Source Code
type Msg
= TriggerFadeIn
| GotAnimMsg WAAPI.AnimMsg
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
GotAnimMsg animMsg ->
let
( animState, maybeEvent ) =
WAAPI.update animMsg model.animState
in
( { model | animState = animState }, Cmd.none )
_ ->
( model, Cmd.none )
subscriptions : Model -> Sub Msg
subscriptions model =
WAAPI.subscriptions GotAnimMsg model.animState
In Detail¶
Initialize¶
The WAAPI engine communicates through two ports: one outgoing (Elm → JS) and one incoming (JS → Elm). Define them in your port module, then pass them to init along with property initializers.
View Source Code
port module Main exposing (main)
import Json.Encode
-- Outgoing port (Elm → JS): sends all animation commands
port motionCmd : Json.Encode.Value -> Cmd msg
-- Incoming port (JS → Elm): receives all animation messages
port motionMsg : (Json.Encode.Value -> msg) -> Sub msg
init : ( Model, Cmd Msg )
init =
( { animState =
WAAPI.init motionCmd motionMsg
[ Opacity.init "fadeAnim" 0
, Translate.initXY "slideAnim" 100 50
]
}
, Cmd.none
)
📖 See Initialize for more info.
📖 See WAAPI JavaScript for install instructions.
Trigger¶
The WAAPI engine offers two trigger functions: animate for state-tracked animations and fireAndForget for fire-and-forget effects.
animate¶
Use animate when you need state-tracked animations. The engine tracks start values, so subsequent animations always start from the last known position.
View Source Code
fireAndForget¶
Use fireAndForget for one-shot effects where you don't need to pause, resume, query, or interrupt. It takes the port function directly and returns a bare Cmd msg with no state to store.
📖 See Triggering Animations for more info.
Mid-Flight Interruptions¶
WAAPI keeps runtime animation state, so interrupting a running animation continues smoothly from the current in-flight position.
📖 See Interrupting Animations for more info.
OnLoad Animations¶
For on-load animations, trigger animate when the page initializes, the animation runs immediately.
Update¶
Use update to process incoming WAAPI messages. It returns the updated AnimState and a Maybe AnimEvent.
View Source Code
Events¶
The WAAPI, ScrollTimeline and ViewTimeline Engines all utilize the JavaScript Web Animations API, and they all use the same ports to communicate with the JS companion. If you use two or more of these engines in your Elm App, depending on your setup, there is the potential for them all to receive the same messages from JS at the same time, which could be confusing.
The library has you covered here though, all incoming messages are gated by each Engine, which is why update returns a Maybe AnimEvent - Nothing means the message was not for this Engine.
Every event carries the animation group name. Some events carry an additional value:
CancelledandPausedinclude the progress at the moment of cancellation/pause (Float, 0.0–1.0)Iterationincludes the iteration count (Int)Progressfires every frame with the current progress (Float, 0.0–1.0)AnimErrorcarries an error string from the JavaScript layer
View Source Code
| Event | Fires when... |
|---|---|
Started |
Animation begins playing |
Ended |
Animation completes |
Cancelled |
Animation is interrupted by something outside the engine's control. |
Iteration |
Each iteration completes (looping or alternating) |
Progress |
Every frame while the animation is running |
Paused |
pause is called on a running animation |
Resumed |
resume is called on a paused animation |
Restarted |
restart is called |
AnimError |
The JavaScript layer reports an error |
Subscriptions¶
The WAAPI engine requires a subscription to receive animation events from JavaScript. Without it, animations still play visually but Elm won't receive events and AnimState will be out of sync.
View Source Code
📖 See React for more info.
View¶
Apply attributes to the animated element.
📖 See Render for more info.
Responsive Strategy¶
Use relative CSS units whenever the motion can be defined in layout-relative terms.
For measured pixel targets, WAAPI supports proportional remap for resize updates.
- On resize, update bounds with
onResizeandTranslate.bounds/Scale.bounds/PerspectiveOrigin.bounds. - Running animations remap to the equivalent relative position inside the updated bounds.
- Idle animations also re-position proportionally inside the updated bounds.
📖 See Responsive Animations for more info.
Playback¶
Set iterations, loopForever, and alternate in the animation builder.
View Source Code
📖 See Playback for the full looping, iterations, and alternate API with live examples.
Timing¶
Set the default duration, speed, and delay. Inherited by every property that doesn't override them.
duration— animation length in milliseconds.speed— alternative toduration; set a rate in property units per second.delay— wait before the animation begins, in milliseconds.
View Source Code
📖 See Timing for more info.
Easing¶
WAAPI animations support the full Easing library, including bounce and elastic. Simple curves (sine, quad, cubic, quart, quint, expo) are handed to the browser as native easing functions. Complex curves (bounce, elastic) are sampled into densely-spaced stops, and the browser interpolates linearly between them — visually faithful to the source curve.
Set the default easing for all properties that don't override it:
View Source Code
📖 See Easing for all available easing functions.
Spring¶
WAAPI animations support springs. The spring's motion is pre-baked into densely-spaced keyframe stops on the Elm side, and the browser interpolates linearly between them — visually faithful to the analytic solution.
Set the default spring for all properties that don't override it: The motion ends when each value has settled at the target — there is no explicit duration.
View Source Code
📖 See Spring for the full preset list and tuning guidance.
Controls¶
All WAAPI control functions return ( AnimState msg, Cmd msg ) — the Cmd is dispatched to JavaScript to drive the underlying Web Animation.
| Function | Description |
|---|---|
stop |
Jump to end state |
reset |
Jump to start state |
restart |
Reset and begin playing again |
pause |
Freeze at current position |
resume |
Continue from paused position |
📖 See Controlling Animations for more info.
Discrete Properties¶
The WAAPI engine manages discrete properties as inline styles. discreteEntry values are applied immediately when the animation starts, and discreteExit values flip when the animation completes. No additional view setup is needed.
📖 See Discrete Properties for the full API, live examples, and source code.
Transform Order¶
Use transformOrder to set the order in which transform properties are applied.
Call it after for to set the current animation group's order.
Call it before selecting a group to set the global default for groups that do not override it.
View Source Code
📖 See Transform Order for full details.
Freeze Axes¶
Freeze individual axes of transform properties so they remain fixed during an animation. This is useful when animating one axis while holding another in place.
FreezeProperty values: translate, rotate, scale, skew.
View Source Code
Call unfreezeY (or the matching unfreeze* variant) in a subsequent animation to release the frozen axis.
📖 See Freezing Axes with freeze* for more info.
State Queries¶
Query animation state.
View Source Code
WAAPI.anyRunning model.animState -- Maybe Bool
WAAPI.isRunning "box" model.animState -- Maybe Bool
WAAPI.allComplete model.animState -- Maybe Bool
WAAPI.isComplete "box" model.animState -- Maybe Bool
WAAPI.isCancelled "box" model.animState -- Maybe Bool
WAAPI.getProgress "box" model.animState -- Maybe Float (0.0–1.0)
Nothing is returned when no animation exists for the given group.
Property Queries¶
Query the current, start, and end values for any animated property.
View Source Code
Nothing is returned when no animation exists for the given group.
When to Choose This Engine¶
Choose WAAPI when you want browser-native playback with the broadest state-tracked feature set.
- Best for: production animations that need strong control, events, and current-value queries.
- Avoid when: you do not want JavaScript ports or companion setup.
API Quick Reference¶
Types¶
| Type | Description |
|---|---|
AnimState msg |
Tracks animations and their states |
AnimBuilder eng |
Carries all animation configurations |
AnimMsg |
Messages from WAAPI subscription |
AnimEvent |
Events returned by update |
AnimGroupName |
String type alias for the animation group name |
TransformProperty |
Custom transform ordering |
FreezeProperty |
Identifies a transform axis to freeze |
Initialize¶
| Function | Type | Description |
|---|---|---|
init |
(Value -> Cmd msg) -> ((Value -> msg) -> Sub msg) -> List (AnimBuilder eng -> AnimBuilder eng) -> AnimState msg |
Create initial animation state with ports |
Trigger¶
| Function | Type | Description |
|---|---|---|
animate |
AnimState msg -> (AnimBuilder eng -> AnimBuilder eng) -> ( AnimState msg, Cmd msg ) |
Apply a state-tracked animation |
fireAndForget |
(Value -> Cmd msg) -> (AnimBuilder eng -> AnimBuilder eng) -> Cmd msg |
Fire a stateless animation |
Events¶
| Event | Description |
|---|---|
Started AnimGroupName |
Animation begins playing |
Ended AnimGroupName |
Animation completes |
Cancelled AnimGroupName Float |
Animation cancelled; Float is progress at cancellation |
Restarted AnimGroupName |
Animation is restarted |
Paused AnimGroupName Float |
Animation paused; Float is progress at pause |
Resumed AnimGroupName |
Animation resumed |
Iteration AnimGroupName Int |
Loop iteration completes; Int is iteration count |
Progress AnimGroupName Float |
Each frame; Float is current progress (0.0–1.0) |
AnimError String |
JavaScript-layer error |
Update¶
| Function | Type | Description |
|---|---|---|
update |
AnimMsg -> AnimState msg -> ( AnimState msg, Maybe AnimEvent ) |
Process WAAPI messages |
Subscriptions¶
| Function | Type | Description |
|---|---|---|
subscriptions |
(AnimMsg -> msg) -> AnimState msg -> Sub msg |
Subscribe to WAAPI events from JavaScript |
View¶
| Function | Type | Description |
|---|---|---|
attributes |
AnimGroupName -> AnimState msg -> List (Html.Attribute msg) |
Get animation attributes for an element |
Playback¶
| Function | Type | Description |
|---|---|---|
iterations |
Int -> AnimBuilder eng -> AnimBuilder eng |
Set number of iterations |
loopForever |
AnimBuilder eng -> AnimBuilder eng |
Loop animation infinitely |
alternate |
AnimBuilder eng -> AnimBuilder eng |
Reverse direction on each iteration |
Timing¶
| Function | Type | Description |
|---|---|---|
duration |
Int -> AnimBuilder eng -> AnimBuilder eng |
Set duration (ms) |
speed |
Float -> AnimBuilder eng -> AnimBuilder eng |
Set speed (property units/sec) |
delay |
Int -> AnimBuilder eng -> AnimBuilder eng |
Set delay before animation starts (ms) |
Easing¶
| Function | Type | Description |
|---|---|---|
easing |
Easing -> AnimBuilder eng -> AnimBuilder eng |
Set easing function |
Spring¶
| Function | Type | Description |
|---|---|---|
spring |
Spring -> AnimBuilder eng -> AnimBuilder eng |
Set spring physics |
Controls¶
| Function | Type | Description |
|---|---|---|
pause |
AnimGroupName -> AnimState msg -> ( AnimState msg, Cmd msg ) |
Freeze at current position |
resume |
AnimGroupName -> AnimState msg -> ( AnimState msg, Cmd msg ) |
Continue from paused position |
stop |
AnimGroupName -> AnimState msg -> ( AnimState msg, Cmd msg ) |
Jump to end state and stop |
reset |
AnimGroupName -> AnimState msg -> ( AnimState msg, Cmd msg ) |
Jump to start state and stop |
restart |
AnimGroupName -> AnimState msg -> ( AnimState msg, Cmd msg ) |
Reset and begin playing again |
Discrete Properties¶
| Function | Type | Description |
|---|---|---|
discreteEntry |
String -> String -> AnimBuilder eng -> AnimBuilder eng |
Set a CSS property value when the animation starts |
discreteExit |
String -> String -> String -> AnimBuilder eng -> AnimBuilder eng |
Set a CSS property value during and after the animation |
Transform Order¶
| Function | Type | Description |
|---|---|---|
transformOrder |
List TransformProperty -> AnimBuilder eng -> AnimBuilder eng |
Set custom transform order |
Freeze Axes¶
| Function | Type | Description |
|---|---|---|
translate |
FreezeProperty |
Target translate for freezing |
rotate |
FreezeProperty |
Target rotate for freezing |
scale |
FreezeProperty |
Target scale for freezing |
skew |
FreezeProperty |
Target skew for freezing |
freezeX |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Freeze X axis of specified properties |
freezeY |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Freeze Y axis |
freezeZ |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Freeze Z axis |
freezeXY |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Freeze X and Y axes |
freezeXZ |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Freeze X and Z axes |
freezeYZ |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Freeze Y and Z axes |
freezeXYZ |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Freeze all axes |
unfreezeX |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Unfreeze X axis |
unfreezeY |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Unfreeze Y axis |
unfreezeZ |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Unfreeze Z axis |
unfreezeXY |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Unfreeze X and Y axes |
unfreezeXZ |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Unfreeze X and Z axes |
unfreezeYZ |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Unfreeze Y and Z axes |
unfreezeXYZ |
List FreezeProperty -> AnimBuilder eng -> AnimBuilder eng |
Unfreeze all axes |
State Queries¶
| Function | Type | Description |
|---|---|---|
anyRunning |
AnimState msg -> Maybe Bool |
Check if any animation is running |
isRunning |
AnimGroupName -> AnimState msg -> Maybe Bool |
Check if a specific group is animating |
allComplete |
AnimState msg -> Maybe Bool |
Check if all animations are complete |
isComplete |
AnimGroupName -> AnimState msg -> Maybe Bool |
Check if a specific group's animation is complete |
isCancelled |
AnimGroupName -> AnimState msg -> Maybe Bool |
Check if a specific group's animation was cancelled |
getProgress |
AnimGroupName -> AnimState msg -> Maybe Float |
Get current progress (0.0–1.0) |
Property Queries¶
| Function | Type | Description |
|---|---|---|
getOpacityStart |
AnimGroupName -> AnimState msg -> Maybe Float |
Get start opacity |
getOpacityEnd |
AnimGroupName -> AnimState msg -> Maybe Float |
Get end opacity |
getOpacityCurrent |
AnimGroupName -> AnimState msg -> Maybe Float |
Get current opacity |
getTranslateStart |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get start translate |
getTranslateEnd |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get end translate |
getTranslateCurrent |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get current translate |
getRotateStart |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get start rotate |
getRotateEnd |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get end rotate |
getRotateCurrent |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get current rotate |
getScaleStart |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get start scale |
getScaleEnd |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get end scale |
getScaleCurrent |
AnimGroupName -> AnimState msg -> Maybe { x, y, z } |
Get current scale |
getSizeStart |
AnimGroupName -> AnimState msg -> Maybe { width, height } |
Get start size |
getSizeEnd |
AnimGroupName -> AnimState msg -> Maybe { width, height } |
Get end size |
getSizeCurrent |
AnimGroupName -> AnimState msg -> Maybe { width, height } |
Get current size |
getSkewStart |
AnimGroupName -> AnimState msg -> Maybe { x, y } |
Get start skew |
getSkewEnd |
AnimGroupName -> AnimState msg -> Maybe { x, y } |
Get end skew |
getSkewCurrent |
AnimGroupName -> AnimState msg -> Maybe { x, y } |
Get current skew |
getPropertyStart |
AnimGroupName -> String -> AnimState msg -> Maybe Float |
Get start value for a custom numeric property |
getPropertyEnd |
AnimGroupName -> String -> AnimState msg -> Maybe Float |
Get end value for a custom numeric property |
getPropertyCurrent |
AnimGroupName -> String -> AnimState msg -> Maybe Float |
Get current value for a custom numeric property |
getColorPropertyStart |
AnimGroupName -> String -> AnimState msg -> Maybe Color |
Get start value for a custom color property |
getColorPropertyEnd |
AnimGroupName -> String -> AnimState msg -> Maybe Color |
Get end value for a custom color property |
getColorPropertyCurrent |
AnimGroupName -> String -> AnimState msg -> Maybe Color |
Get current value for a custom color property |
Nothing is returned when no animation exists for the given group.
For complete API details, see the Anim.Engine.WAAPI documentation.
Next Steps¶
Explore the related timeline engines:
Scroll Timeline Engine Or View Timeline Engine
Or review migration paths and tradeoffs.