A state-interface program that can run in the browser
program : { initialState : state, interface : state -> Interface state, ports : { toJs : Json.Encode.Value -> Platform.Cmd.Cmd Basics.Never, fromJs : (Json.Encode.Value -> ProgramEvent state) -> Platform.Sub.Sub (ProgramEvent state) } } -> Program state
Create a Program
:
The state is everything the program knows (what The Elm Architecture calls model).
And it always starts with a given initialState
The Interface
is the face to the outside world
and can be created using the helpers in Web.Dom
, Web.Time
, Web.Http
etc.
The given interface
function constructs these interfaces based on the current state
Connections to and from js
port toJs : Json.Encode.Value -> Cmd event_
port fromJs : (Json.Encode.Value -> event) -> Sub event
Rope (InterfaceSingle future)
Incoming and outgoing effects.
To create one, use the helpers in Web.Time
, Web.Dom
, Web.Http
etc.
To combine multiple, use Web.interfaceBatch
and Web.interfaceNone
.
To change the value that comes back in the future, use Web.interfaceFutureMap
interfaceBatch : List (Interface future) -> Interface future
Combine multiple Interface
s into one
interfaceNone : Interface future_
Doing nothing as an Interface
. These two examples are equivalent:
Web.interfaceBatch [ a, Web.interfaceNone, b ]
and
Web.interfaceBatch
(List.filterMap identity
[ a |> Just, Nothing, b |> Just ]
)
Types used by Web.Dom
RecordWithoutConstructorFunction { namespace : Maybe String
, tag : String
, styles : Dict String String
, attributes : Dict String String
, attributesNamespaced : Dict ( String
, String ) String
, stringProperties : Dict String String
, boolProperties : Dict String Basics.Bool
, scrollToPosition : Maybe { fromLeft : Basics.Float
, fromTop : Basics.Float }
, scrollToShow : Maybe { x : DomElementVisibilityAlignment
, y : DomElementVisibilityAlignment }
, scrollPositionRequest : Maybe ({ fromLeft : Basics.Float
, fromTop : Basics.Float } -> future)
, eventListens : Dict String { on : Json.Decode.Value -> future
, defaultActionHandling : DefaultActionHandling }
}
Everything about a tagged DOM element except potential sub-nodes
What part of the Web.Dom.Element
should be visible
DomElementStart
: mostly for text to readDomElementEnd
: mostly for text to writeDomElementCenter
: mostly for imagesSetting for a listen Web.Dom.Modifier
to keep or overwrite the browser's default action
Types used by Web.Audio
RecordWithoutConstructorFunction { url : String
, startTime : Time.Posix
, volume : AudioParameterTimeline
, speed : AudioParameterTimeline
, stereoPan : AudioParameterTimeline
, processingLastToFirst : List AudioProcessing
}
Some kind of sound we want to play. To create Audio
, start with Web.Audio.fromSource
RecordWithoutConstructorFunction { url : String
, duration : Duration
}
Audio data we can use to play sounds.
Use Web.Audio.sourceLoad
to fetch an AudioSource
.
You can also use the contained source duration
, for example to find fade-out times or to create a loop:
audioLoop : AudioSource -> Time.Posix -> Time.Posix -> Audio
audioLoop source initialTime lastTick =
Web.Audio.fromSource source
(Duration.addTo
initialTime
(source.duration
|> Quantity.multiplyBy
(((Duration.from initialTime lastTick |> Duration.inSeconds)
/ (source.duration |> Duration.inSeconds)
)
|> floor
|> toFloat
)
)
)
These are possible errors we can get when loading an audio source file.
AudioSourceLoadDecodeError
: This means we got the data but we couldn't decode it. One likely reason for this is that your url points to the wrong place and you're trying to decode a 404 page instead.AudioSourceLoadNetworkError
: We couldn't reach the url. Either it's some kind of CORS issue, the server is down, or you're disconnected from the internet.A single effect filter applied to an Audio
{ startValue : Basics.Float
, keyFrames : List { time : Time.Posix
, value : Basics.Float }
}
defining how loud a sound should be at any point in time
Types used by Web.Http
RecordWithoutConstructorFunction { url : String
, method : String
, headers : List { name : String
, value : String }
, body : HttpBody
, expect : HttpExpect future
}
An HTTP request for use in an Interface
.
Use Web.Http.addHeaders
to set custom headers as needed.
Use Web.Time.onceAt
to add a timeout of how long you are willing to wait before giving up.
Data send in your http request.
HttpBodyEmpty
: Create an empty body for your request.
This is useful for GET
requests and POST
requests where you are not sending any data.
HttpBodyString
: Put a String
in the body of your request. Defining Web.Http.jsonBody
looks like this:
import Json.Encode
jsonBody : Json.Encode.Value -> Web.HttpBody
jsonBody value =
Web.HttpBodyString "application/json" (Json.Encode.encode 0 value)
The first argument is a MIME type of the body.
HttpBodyUnsignedInt8s
is pretty much the same as HttpBodyString
but for Bytes
,
see Web.Http.bodyBytes
Describe what you expect to be returned in an http response body.
A Request can fail in a couple ways:
BadUrl
means you did not provide a valid URLNetworkError
means the user turned off their wifi, went in a cave, etc.
or the server CORS is misconfigured.
Note: A 404 for example does not constitute a network errorBadStatus
means you got a response back, but the status code indicates failure. Contains:Metadata
.Json.Decode.Value
.RecordWithoutConstructorFunction { url : String
, statusCode : Basics.Int
, statusText : String
, headers : Dict String String
}
Extra information about the response:
Note: It is possible for a response to have the same header multiple times. In that case, all the values end up in a single entry in the headers dictionary. The values are separated by commas, following the rules outlined here.
Types used by Web.Socket
An indication that connection has changed
after having initiated Web.Socket.connectTo
.
SocketConnected
: connection has been opened. Gives access to a Web.SocketId
SocketDisconnected
: connection has been closed withcode
sent by the serverreason
indicating why the server closed the connection, specific to the particular server and sub-protocolIdentifier for a Web.Socket
that can be used to communicate
Types used by Web.GeoLocation
RecordWithoutConstructorFunction { latitudeInDecimalDegrees : Basics.Float
, longitudeInDecimalDegrees : Basics.Float
, latitudeLongitudeAccuracy : Maybe Length
, altitudeAboveNominalSeaLevel : Maybe Length
, altitudeAccuracy : Maybe Length
, headingWith0AsTrueNorthAndIncreasingClockwise : Maybe Angle
, speed : Maybe Speed
}
Position and (if available) altitude of the device on Earth, as well as the accuracy with which these properties are calculated. The geographic position information is provided in terms of World Geodetic System coordinates (WGS84).
Device movement direction and speed might also be provided.
Length
,
Angle
and
Speed
are from ianmackenzie/elm-units
Types used by Web.Gamepads
RecordWithoutConstructorFunction { primaryButton : GamepadButton
, secondaryButton : GamepadButton
, tertiaryButton : GamepadButton
, quaternaryButton : GamepadButton
, leftBumperButton : GamepadButton
, rightBumperButton : GamepadButton
, leftTriggerButton : GamepadButton
, rightTriggerButton : GamepadButton
, selectButton : GamepadButton
, startButton : GamepadButton
, leftThumbstickButton : GamepadButton
, rightThumbstickButton : GamepadButton
, upButton : GamepadButton
, downButton : GamepadButton
, leftButton : GamepadButton
, rightButton : GamepadButton
, homeButton : GamepadButton
, touchpadButton : GamepadButton
, additionalButtons : List GamepadButton
, kindId : String
, thumbstickLeft : { x : Basics.Float
, y : Basics.Float }
, thumbstickRight : { x : Basics.Float
, y : Basics.Float }
, thumbsticksAdditional : List { x : Basics.Float
, y : Basics.Float }
}
Controller information on button presses, thumbstick positions etc.
primaryButton
: The most common action like "enter"/"confirm" or jump
secondaryButton
: Usually "cancel"/"skip" or a common ability like duck/sneak, drop or heal
tertiaryButton
: common-ish ability like consume, interact, reload or an ultimate power
quaternaryButton
: less common action like quick menu or mode switch
leftBumperButton
, rightBumperButton
: The top row of smaller buttons on the side opposite of you, sometimes called shoulder buttons.
Often used for alternative menu actions like slot switching or quick map
leftTriggerButton
, rightTriggerButton
: The bottom row of larger buttons on the side opposite of you.
Often used for holdable abilities like sliding or dashing
selectButton
: Usually opens an in-world menu with for example inventory, lore, ability overview or a map
startButton
: Usually pauses the game and opens a menu with options like settings and quit
leftThumbstickButton
, rightThumbstickButton
: Not all gamepads have these, so they often either double existing actions like "confirm"
or perform actions that are only very rarely helpful, like hiding ui elements or making a screenshot
upButton
, downBottom
, leftButton
, rightButton
: exactly one step in a direction, usually in a (quick) menu/inventory
homeButton
: Usually turns the gamepad on/off, or changes the state of the game
touchpadButton
: Not present on most gamepads. While the touchpad is often used for controlling the mouse, it can also be used as a simple button
thumbstickLeft
, thumbstickRight
: Those wiggly that can be moved in any direction by any amount.
They are provided as x, y
signed percentages
kindId
: some information about the gamepad, usually containing the USB vendor, product id of the gamepad
and the name of the gamepad as provided by the driver. See mdn
You can use this information to for example determine how to show controls
buttonsAdditional
, thumbsticksAdditional
: Maybe you have a weird gamepad with 3 thumbsticks? These might help 🤷
Implementation note: As you know, gamepad layouts differ between models. For most of them, we're able to map them to the buttons and thumbsticks above. If you experience issues with some model, open an issue
Buttons are either held down with an optional value between 0 and 1 to measure how hard, or they are released with an optional detection of touch which defaults to false.
Types used by Web.Notification
The user clicked a displayed notification, moving the focus to our page
Types used by Web.Window
The visibility to the user
WindowHidden
: the user has navigated to a new page, switched tabs, closed the tab, minimized or closed the browser, or, on mobile, switched from the browser to a different appWindowShown
otherwiseIf you just want to replace a part of your elm app with this architecture. Make sure to wire in all 3:
RecordWithoutConstructorFunction { initialState : state
, interface : state -> Interface state
, ports : { toJs : Json.Encode.Value -> Platform.Cmd.Cmd Basics.Never
, fromJs : (Json.Encode.Value -> ProgramEvent state) -> Platform.Sub.Sub (ProgramEvent state) }
}
What's needed to create a state-interface program
programInit : ProgramConfig state -> ( ProgramState state, Platform.Cmd.Cmd (ProgramEvent state) )
The "init" part for an embedded program
programUpdate : ProgramConfig state -> ProgramEvent state -> ProgramState state -> ( ProgramState state, Platform.Cmd.Cmd (ProgramEvent state) )
The "update" part for an embedded program
Exposed so can for example simulate it more easily in tests, add a debugger etc.
The "model" in a Web.program
The "msg" in a Web.program
A "non-batched" Interface
.
To create one, use the helpers in Web.Time
, Web.Dom
, Web.Http
etc.
interfaceSingleEdits : { old : InterfaceSingle future, updated : InterfaceSingle future } -> List InterfaceSingleEdit
What InterfaceSingleEdit
s are needed to sync up
Individual message to js to sync up with the latest interface type, describing changes to an existing interface with the same identity
What parts of an Audio
are replaced