Ode to Elm
Forgotten projects like a good wine. Longer you not touch, better they become.
In this article, you will learn how to build a small game using Elm. I hope my example will inspire you to try it.
From time to time, I like to rest from a working routine and do my hobby: create casual games. Usually, this kind of project started suddenly, paused unexpectedly, rarely finished, and never released. Sometimes I use ReactNative, sometimes Elm.
If you ask me what Elm is, yes, this is a language. But at the same time, it’s also a framework. You write Elm code and a primary result of it — web application of Elm Architecture. This is why eventually Elm is a frameguage or a languwork :-)
What doing Elm so sexy? Here is my top.
Design is fundamental. Elm was designed using an interactive pattern of unidirectional data flow. Not every simple thing is genius. But all genius things are simple.
Looks very familiar, right? All modern frontend developers know about Flux and Redux, which’s based on the concept, where the state is managed by the unified data flow. True, because…
Redux have been inspired by The Elm Architecture.
Elm was created in 2012, a wonderful year when Bootstrap 2 introduced twelve-column responsive grids; Flux came in 2014; Redux in 2015.
Fact that so many frameworks are based on the same concept, proofs that the concept is damn great
Instead of my words, let the Elm code speak. Just take a look, how not to fall in love with all these pipes and arrows?!
In this code snippet, I‘ve created a custom implementation of a generic reduce function. It can aggregate integer values into a sum…
reduce add 0 [ 1, 2, 3 ] => 6
…or “dashify” a list of strings.
reduce dashify "" [ "e", "l", "m" ] => "e-l-m"
I like how pure Elm syntax is. If you are already interested — here is minimal Syntax documentation. It will not take too much time, believe me
I am a lazy ass. I decided not to write a single test for my game. At the same time, I want to have a result with the quality of a USSR spacecraft. For this reason, for me, Elm is like a Christmas gift.
Why? Because one of the best Elm features is — zero exceptions in runtime. Once your Elm code is successfully compiled — it will work without runtime exceptions forever and ever.
Anyway, to prevent logical bugs in your application, you still need to write unit-tests. Tests are standard, the same as everywhere.
It is also super easy to develop and refactor code again and again with Elm. The compiler is the best friend of Elm developer. You add a new feature, compiler guides you on code fixes. Pure pleasure.
Now lets ‘s talk about Elm game dev!
My game is based on a folk game from my childhood: edible-uneatable. The core of my game was created at the begging of 2020 and only at the end of the year I finished the game. GitHub repository of the game is here.
How to play?
You need to feed three hungry guys. Rules are simple: Choose a hero and eat some food based on the hero’s food preferences. Collect as many points as you can. Be careful — you have only 3 health points. Tap to play
The whole game can be written as one single Main.elm file. My game took around 800 lines of code. Write a whole app in a single file is a classic Elm style.
Elm application of your game can be embedded into HTML and run from js side in this way:
Flags is a technique to pass data from the external world into Elm application on application start. My game is built for mobile phones, so I show a “Not Supported” message for wide screens. To tell the program size of the screen, I sent a flag of window.screen.width value.
There are two main screens in the game: SelectHero — a modal popup and Play screen.
Elm program with a skeleton of Elm Architecture methods:
Init — read flags (Int value of width) and return an initial state of the Model. View — render HTML based on the current Model state. Update — the place to handle events by reacting to Messages. The loop of a MVU looks like this:
- A user interacts with HTML (click the button, for example)
- Message is sent to Update
- Update change a Model state to a new one
- View render HTML by a new Model state. …User do something again.
Elm application state is represented by a Model. In my game Model keep information about the next things:
- What game screen to show
- What hero is selected
- What food is shown
- How many Points and Health points (Hp) player have
- Player's BestResults for each hero
Update function contains application business logic. Update changes the Model state based on upcoming messages. Message — is a custom type, that is sent to the Update function by UI events (button click, mouse over, input change, and so on).
For every application event, you create a Message and add a handler in the Update function.
I left all functions empty just to show you a skeleton.
If you are interested in how everything in my game works — take a look at this StateMachine style.
In Elm you not working with HTML directly, you working with a virtual DOM via functions.
When update function complete, Elm executes view function to render HTML using special Html functions. Elm is all about functions, remember that.
div  
Function div with 2 arguments: list of attributes and list of child nodes.
div [ style "padding" "5px" ]
[ p  [ text "1" ]
, span  [ text "2" ]
=> <div style="padding: 5px;"><p>1</p><span>2</span></div>
I am not a markup guru, so I mix my ugly styling with a wonderful CSS Framework called Bulma. It is simple to use and powerful enough to create all the layouts, cards, grids, typography, and other stuff for my game. 100% recommend to try, you can learn Bulma just in few days.
The last game example is a function, that sends an array of heroes into an anonymous function to map hero objects into Bulma Cards.
It wasn’t hard, is not it? I hope that my small story is a good example of how easy and interesting coding in Elm.
Clap-clap-clap for a long life of Elm indie game development!