A state-interface program that can run in the browser
A Platform.Program
that elm can run,
produced by Web.program
You can also embed a state-interface program as part of an existing app that uses The Elm Architecture.
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
Combine multiple Interfaces into one
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 ]
)Take what the Interface can come back with and return a different future value.
In practice, this is sometimes used like a kind of event-config pattern:
Web.Time.posixRequest
|> Web.interfaceFutureMap (\timeNow -> TimeReceived timeNow)
button "show all entries"
|> Web.Dom.render
|> Web.interfaceFutureMap (\Pressed -> ShowAllEntriesButtonClicked)sometimes as a way to deal with all events (like update in The Elm Architecture)
...
|> Web.interfaceFutureMap
(\event ->
case event of
MouseMovedTo newMousePoint ->
{ state | mousePoint = newMousePoint }
CounterDecreaseClicked ->
{ state | counter = state.counter - 1 }
CounterIncreaseClicked ->
{ state | counter = state.counter + 1 }
)and sometimes to nest events (like Cmd.map/Task.map/Sub.map/... in The Elm Architecture):
type Event
= DirectoryTreeViewEvent TreeUiEvent
| SortButtonClicked
type TreeUiEvent
= Expanded TreePath
| Collapsed TreePath
interface : State -> Interface State
interface state =
...
[ treeUi ..
|> Web.interfaceFutureMap DirectoryTreeViewEvent
, ...
]
|> Web.Dom.render
treeUi : ... -> Web.Dom.Node TreeUiEventIn all these examples, you end up converting the narrow future representation of part of the interface to a broader representation for the parent interface
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
Some kind of sound we want to play. To create Audio, start with Web.Audio.fromSource
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
defining how loud a sound should be at any point in time
Types used by Web.Http
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.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. 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.SocketIdSocketDisconnected: 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
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.
Types used by Web.Gamepads
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:
What's needed to create a state-interface program
The "init" part for an embedded program
The "update" part for an embedded program
The "subscriptions" part for an embedded program
Under the hood, Web.program is then defined as just
program config =
Platform.worker
{ init = \() -> Web.programInit yourAppConfig
, update = Web.programUpdate yourAppConfig
, subscriptions = Web.programSubscriptions yourAppConfig
}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
Plain text or a DomElementHeader for use in an Interface.
Alternative to Dict optimized for fast merge and fast creation.
Would be a terrible fit if we needed fast insert and get.
Fold the lists of 2 SortedKeyValueLists depending on where keys are present.
The idea and API is the same as Dict.merge
To simulate diffing of interfaces, use
Web.sortedKeyValueListMerge
(\id toAdd -> ..add toAdd..)
(\id old updated -> ..edit (interfaceSingleEdits { old, updated })..)
(id toRemove -> ..remove toRemove..)
updatedInterfaces
oldInterfaces
..what you fold into..What InterfaceSingleEdits 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
What parts of a node are replaced. Either all modifiers of a certain kind or the whole node
If you need more things like json encoders/decoders, open an issue
Create a
Program:The state is everything the program knows (what The Elm Architecture calls model). And it always starts with a given
initialStateThe
Interfaceis the face to the outside world and can be created using the helpers inWeb.Dom,Web.Time,Web.Httpetc. The giveninterfacefunction constructs these interfaces based on the current stateConnections to and from js