<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: sheosi</title>
    <description>The latest articles on Forem by sheosi (@sheosi).</description>
    <link>https://forem.com/sheosi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F516239%2F8123c873-63b7-4ca0-9624-82f3ea84638a.png</url>
      <title>Forem: sheosi</title>
      <link>https://forem.com/sheosi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sheosi"/>
    <language>en</language>
    <item>
      <title>A delightful OS - The kernel</title>
      <dc:creator>sheosi</dc:creator>
      <pubDate>Thu, 26 Sep 2024 20:40:33 +0000</pubDate>
      <link>https://forem.com/sheosi/a-delightful-os-the-kernel-3773</link>
      <guid>https://forem.com/sheosi/a-delightful-os-the-kernel-3773</guid>
      <description>&lt;p&gt;Hi, my name is Sergio, and...&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have a dream, I'm here to tell, about a fantastic new OS...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So yup, I'm one of those that will perfectly spend hours on end to make something just so that it is ✨perfect©️✨. And yeah, this has been for years on my head, so it is almost time to at least write somewhere.&lt;/p&gt;

&lt;p&gt;So what do we want to build? An OS, for desktop usage, like the one you are using, which is probably either Linux or Android (let's be honest you are reading a guy's rambling about which pieces would make for a better OS, chances are you are a nerd too). Now, how is this OS? as I like to put it &lt;strong&gt;delightful&lt;/strong&gt;💫, an OS that's snappy, secure, private ... Wait maybe it is better if we define what it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Performant: The OS must feel snappy, fast as it can be, extracting the juice from your computer, whether it's old with cobwebs or shiny new.&lt;/li&gt;
&lt;li&gt;Easy to use: It is a desktop, and we've had enough of OS for the savy, if we want people to move here it's gotta be easy (besides, there's a point that even I find it tiring to seSo arch the internet the commands needed for something).&lt;/li&gt;
&lt;li&gt;Solid as metal (the material not the API): It's not funny when your computer won't boot up because itself thought a good idea to update, or because in the middle of the update stupid electrity went off.&lt;/li&gt;
&lt;li&gt;Secure and private: My computer, my data, thank you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most probably I'll be updating those.&lt;/p&gt;

&lt;p&gt;So yup, we know what we want, in a nutshell pretty much what every single of the dozens of user-friendly Linux distributions out there want.&lt;/p&gt;

&lt;h3&gt;
  
  
  So how are we going to build it?
&lt;/h3&gt;

&lt;p&gt;One option could be to make everything from scratch, but since that effort takes several years of hundreds of engineers to achieve such state and my &lt;em&gt;possible&lt;/em&gt; group of engineers ammounts to ... let me count ... one, taking as much done as possible seems like a great idea.&lt;/p&gt;

&lt;p&gt;Let's look at the contenders&lt;/p&gt;

&lt;h2&gt;
  
  
  macOS and Windows
&lt;/h2&gt;

&lt;p&gt;I know, I know, already there, and might not be an option, but they exist, and might be the solution for a lot people, which is fine. I feel like they have their own set of problems, namely tied to a company trying to sell you as much as they can, macOS which was regarded as a holy grail for privacy and non-intrusiveness definetely integrates &lt;em&gt;a lot&lt;/em&gt; their own services, and Microsoft ... is trying to put &lt;a href="https://answers.microsoft.com/en-us/msteams/forum/all/the-new-windows-11-update-now-places-massive-ads/dba680c9-14b4-4a60-9668-a4146aee9075" rel="noopener noreferrer"&gt;ads&lt;/a&gt; everywhere on their OS, plus the whole Recall fiasco ... etc ... &lt;/p&gt;

&lt;p&gt;No use then, but let's not forget that macOS puts out an open source of their kernel called Darwin, which could be useful if we didn't had ...&lt;/p&gt;

&lt;h2&gt;
  
  
  Linux
&lt;/h2&gt;

&lt;p&gt;You knew this was going to happen, Linux is the platform of freedom by default. Most people that are running from macOS and Windows will go into Linux (into one of the thousands available).&lt;/p&gt;

&lt;p&gt;You can argue that its bazaar model (in which everyone develops the **ck they want and someone integrates it, which are known as distribution) is broken, that the whole DKMS (third party kernel modules) as a bit of a mess, that Wayland is slow to being develop ...&lt;/p&gt;

&lt;p&gt;But it has a lot of good, out of the open source kernels it is the one with the best driver support, it is being tackled by tons of developers (improving it making it better), heck it even has the wonderful, incredible and blazingly fast Rust language in it. There's a lot of interesting things going on there, and it's improving at a nice pace.&lt;/p&gt;

&lt;h2&gt;
  
  
  FreeBSD and **BSD in general
&lt;/h2&gt;

&lt;p&gt;As I said I don't like leaving stones unturned. So, I'm not just considering Linux but literally everything out there, so what about the BSDs?&lt;/p&gt;

&lt;p&gt;The BSDs have in their favour a much more organized model, supposedly more stability, and depending on the flavour better performance on different areas. Focusing on FreeBSD (the one closest to desktop usage), we have some nice things there: people speak of a faster OS, faster network IO, less "dissonance" when using their tools, more stability, compatibility with Linux binaries... also there's ZFS, the end all of filesystems, I'm not going to write about it's coolness here, you can duckduckgo it (am I using duckduckgo instead of google as a verb? yes, we need to raise awereness for other engines), but trust me, IT. IS. COOL.&lt;/p&gt;

&lt;p&gt;It's pretty good, however, while the &lt;a href="https://www.phoronix.com/review/bsd-linux-threadripper-7980x/4" rel="noopener noreferrer"&gt;benchmarks&lt;/a&gt; do support some of those claims, for me FreeBSD is like another-linux, and has a lot of missing drivers (which is already a problem with Linux, and I can say that confidently, since I am writing this from my &lt;a href="https://github.com/linux-surface/linux-surface/wiki/Supported-Devices-and-Features#feature-matrix" rel="noopener noreferrer"&gt;Surface&lt;/a&gt; device) and the Linux compatiblity layer is yet another layer of things that can (and will) go wrong when people execute their programs, and I'm not saying this out of some theoric possibility, I've seen some reports of people failling to execute programs on more complex scenarios (like Steam or Proton), scenarios which are super useful today.&lt;/p&gt;

&lt;p&gt;Regarding ZFS we have other options like btrfs that although not as great, exist and are an option, and we also have openZFS, the Linux version of ZFS (AFAIK not as good, but again an option).&lt;/p&gt;

&lt;p&gt;Some might point out the license (GPL vs BSD), and how they consider one to be more free than the other. This is a gasoline topic (one that can sause flames) and I'm not ready for any war, but I'm going to not take it into account, for the actual user there's little difference on those, what's more is that GPL has made some companies to actually make open source software, with great results (like AMD, whose open source driver has better performance and works overall better than it's closed source conterpart), while unfortunately, greed shows no limits, and companies like Sony or Apple have taken BSD software and returned AFAIK, nothing to those code bases.&lt;/p&gt;

&lt;p&gt;Finally, I'm ruling out other BSDs, since they aren't targeted for the desktop.&lt;/p&gt;

&lt;p&gt;So FreeBSD is not a bad option, but definetely would fragment more the space and/or need much more work, and we are willing to put in work...&lt;/p&gt;

&lt;h2&gt;
  
  
  Microkernels
&lt;/h2&gt;

&lt;p&gt;As I said no stones unturned. My feeling is that you are proposing people to change something either what they have is broken and doesn't satisfy them of the new thing must have a good compelling reason.&lt;/p&gt;

&lt;p&gt;And microkernels have this reason.&lt;/p&gt;

&lt;p&gt;For those who dont know what microkernels are. All the other OS are what we call monolithic (or mostly monolithic) and they embed every driver (and other modules) inside of the kernel program itself, even if those modules are loaded per users request they still loaded into the kernel itself, a single bad line in any of them, can make your whole computer say "thanks, enough for today" and ... crash.&lt;/p&gt;

&lt;p&gt;Microkernels fix this by making all of those modules regular programs, which present several advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A crash is a minor problem: A crash will only bring down that part of the computer not anything else. Plus it can be recovered by realoding the program itself.&lt;/li&gt;
&lt;li&gt;No difference in between os-provided drivers and third party ones: Since they are all programs and use the same interface, there's not gonnna be any if some third-party offers a kernel module for their driver, it's gonna work easily since the interfaces are stablished.&lt;/li&gt;
&lt;li&gt;Live updates: Since &lt;strong&gt;everything&lt;/strong&gt; is a normal user space program. Updates could be done live, no more rebooting. The only thing that would require a reboot would be the microkernel itself, which is pretty small (some ammount to 3k lines), so it is reasonable to think that the updates here after a couple of versions would rare, besides live patching could be possible, Linux does it, and I argue that for such a small program it would be even easier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Which ones to focus on then? There are two names out there that i find most interesting nowadays: RedoxOS (written in Rust, great momentum, interesting concepts, some good projects beneath it) and SculptOS (ability to use multiple, different kernels, interesting sandboxing system ...), I still have to try them out before I can say which one I find more promising as far as desktop goes, but those two are the best candidates I know.&lt;/p&gt;

&lt;p&gt;Again, just for the completion there are others like HelenOS, but either they aren't desktop-focused at all or they are too far behind to be even considered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is there anything else?
&lt;/h2&gt;

&lt;p&gt;Yeah, there's a lot out there (MenuetOS, HaikuOS, ReactOS, ...) and they are widly interesting, if you are curious, do take a look at them. But for me they fall under the same category as FreeBSD, they would require a ton of work to make them consumer-grade desktop friendly.&lt;/p&gt;

&lt;p&gt;The only other concept that's interesting is the one of the distributed OSs, where a bunch of machines are linked together and they can use each other's resources, imagine taking a picture from your computer using your phone's camera, or accessing their files transparently. This super interesting, but the level that we are interested in can be implemented in standard OSs, the only thing that we wouldn't be able to replicate would be things like RAM sharing and programs that work on both devices at the same time, things which are hardly useful since they require connection systems unavailable to consumer-grade devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;p&gt;Linux is the one closest to being able to be used, with newer microkernels (Redox and Sculpt) showing promise.&lt;/p&gt;

&lt;p&gt;Now, there's still a ton of other questions to be asked on our marvelous OS but for the time being we know how we are going to base it.&lt;/p&gt;

&lt;p&gt;Don't agree with something? Would love hear your opinion on a comment. Have a great day!&lt;/p&gt;

</description>
      <category>osdev</category>
      <category>linux</category>
    </item>
    <item>
      <title>Making a game (engine) with ECS and in OCaml</title>
      <dc:creator>sheosi</dc:creator>
      <pubDate>Sun, 11 Jul 2021 23:06:40 +0000</pubDate>
      <link>https://forem.com/sheosi/making-a-game-engine-with-ecs-and-in-ocaml-2oma</link>
      <guid>https://forem.com/sheosi/making-a-game-engine-with-ecs-and-in-ocaml-2oma</guid>
      <description>&lt;p&gt;Hi!👋🏻️ My name's Sergio, and I had kind of a dream: how would a &lt;em&gt;game&lt;/em&gt; engine look if it were made in a &lt;em&gt;functional&lt;/em&gt; style? 🤔️ Also, every project implementing a framework needs something to do, so I went with the game style of &lt;em&gt;Megaman Battle Network&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Language
&lt;/h1&gt;

&lt;p&gt;The language I wanted to use was &lt;em&gt;OCaml&lt;/em&gt;, the ⭐️ star of the show in the &lt;em&gt;ML&lt;/em&gt; family. I know &lt;em&gt;F#&lt;/em&gt; exists (and have used it too), but wanted to try &lt;em&gt;OCaml&lt;/em&gt; in itself, functors, object model and their venerable compiler.&lt;/p&gt;

&lt;p&gt;Unfortunately, that is hard 😥️... Entering OCaml means you need to understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OPAM&lt;/strong&gt;: 📦️ The package manager&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dune&lt;/strong&gt;: 🔨️ The build system&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OCaml&lt;/strong&gt;: 📋️ The language itself (which is unique and somewhat quirky)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard library&lt;/strong&gt;: 📚️ The included one is pretty basic, and according to some, aging. The problem is that there are &lt;strong&gt;three&lt;/strong&gt; alternatives out there and they are &lt;strong&gt;incompatible&lt;/strong&gt; with each other.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you see &lt;em&gt;OCaml&lt;/em&gt; has opted to have a tool for each need. And while each of those tools are 👌🏼️ top-notch  as they are fast and will cover almost any case you can imagine, they also do very little in terms of integrations and do require some setup.&lt;/p&gt;

&lt;p&gt;Truth being told, saying this is just unfair. This is all true, but also is true that the community is making great ammends in fixing &lt;em&gt;OCaml&lt;/em&gt; holes. Which brings me to...&lt;/p&gt;

&lt;h1&gt;
  
  
  One program to rule them all
&lt;/h1&gt;

&lt;p&gt;After some tries of using &lt;em&gt;OCaml&lt;/em&gt; and having little succes I found &lt;a href="https://ocamlpro.github.io/drom/" rel="noopener noreferrer"&gt;drom&lt;/a&gt;. You see, &lt;em&gt;drom&lt;/em&gt; is to &lt;em&gt;OCaml&lt;/em&gt; what &lt;a href="https://doc.rust-lang.org/cargo/" rel="noopener noreferrer"&gt;&lt;em&gt;cargo&lt;/em&gt;&lt;/a&gt; is to &lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;&lt;em&gt;Rust&lt;/em&gt;&lt;/a&gt;, that is an unified interface for the whole set of tools. Install it with &lt;em&gt;OPAM&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;opam install drom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can make a new program with just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drom new my_program --skeleton program
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That command will also tell which files to edit.&lt;/p&gt;

&lt;p&gt;🙋‍♂️️ Hey, I've changed some of those configuration files, how I make the project react to it? Easy, in the root of your project do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drom project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to see you program in action 🏃‍♀️️:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drom run
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will build it and run it.&lt;/p&gt;

&lt;p&gt;Not everything are roses though, there some thorns as documentation is scarce and some topics like loading a debugger or profiling are not covered yet. But it is a marked improvement over having to learn &lt;em&gt;opam&lt;/em&gt;, &lt;em&gt;opam&lt;/em&gt;'s &lt;em&gt;switches&lt;/em&gt;, &lt;em&gt;dune&lt;/em&gt;, and using all of them. Also, it feels more integrated and less intrusive than &lt;em&gt;esy&lt;/em&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  The game
&lt;/h1&gt;

&lt;p&gt;As I said, the test project I made was a &lt;em&gt;Megaman Battle Network&lt;/em&gt;. Though made is a little big as there's little more than 4 sprites, but already gives an impression of how building the project would feel.&lt;/p&gt;

&lt;p&gt;For those who don't know what &lt;em&gt;Megaman Battle Network&lt;/em&gt; is, let met tell you that is an action &lt;em&gt;RPG&lt;/em&gt; (since there aren't traditional turns in it) where you control what could be called a blue &lt;em&gt;Alexa&lt;/em&gt; deleting viruses and other badies that want to take over the internet. For what I've made is enogh to say that battles are played in a grid. Here, let me show you:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhe6bgymmzjph59iwlup.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdhe6bgymmzjph59iwlup.jpg" alt="Megaman battles some viruses, with you and the enemy getting a set of 3 by 3 squares"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  The engine
&lt;/h1&gt;

&lt;p&gt;As I wanted to make this from scratch I wanted to keep it modern and use an &lt;em&gt;ECS&lt;/em&gt;. &lt;em&gt;ECS&lt;/em&gt; stands for &lt;strong&gt;Entity&lt;/strong&gt;, &lt;strong&gt;Component&lt;/strong&gt;, &lt;strong&gt;System&lt;/strong&gt; and is all the rage these days. The premise is that instead of following the tradition of making an object which contains a &lt;em&gt;Sprite&lt;/em&gt;, it's position, it's health and other parameters, all the data of one kind is held together (there's a table with all the positions from all objects) this brings huge performance wins for a large quantity of objects (100 times better cache usage and possible usage of SIMD) and improves extensibility.&lt;/p&gt;

&lt;p&gt;As for the technology underneath I used Raylib. Raylib is a library with pretty much everything you need to make a game, think of Allegro, SFML or SDL, but:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;is available on &lt;strong&gt;anything&lt;/strong&gt; you can think of&lt;/li&gt;
&lt;li&gt;it covers &lt;strong&gt;everything&lt;/strong&gt;, yeah, even 3D, fonts, networking ...&lt;/li&gt;
&lt;li&gt;is &lt;strong&gt;dead simple&lt;/strong&gt; to use, and have really good documentation&lt;/li&gt;
&lt;li&gt;there are bindings for &lt;strong&gt;any language&lt;/strong&gt; in existance, really.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The code
&lt;/h1&gt;

&lt;p&gt;As you know ECS is divided into Entities, Components and Systems.&lt;br&gt;
&lt;em&gt;Entities&lt;/em&gt; are here nothing more than an &lt;strong&gt;ID&lt;/strong&gt;, a &lt;em&gt;key&lt;/em&gt; that we will use to access the &lt;em&gt;hash tables&lt;/em&gt; where all the data broken into &lt;em&gt;components&lt;/em&gt; is stored, then the systems access any number of components they might need.&lt;/p&gt;
&lt;h2&gt;
  
  
  Components
&lt;/h2&gt;

&lt;p&gt;To get a better example: to render a &lt;em&gt;sprite&lt;/em&gt; we need a position and a sprite to render:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sig&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Sprite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Texture2D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t'&lt;/span&gt; &lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ctyp&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;tex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load_texture&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="nn"&gt;Gc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finalise&lt;/span&gt; &lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unload_texture&lt;/span&gt; &lt;span class="n"&gt;tex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tex&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sig&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we include a base module here (using &lt;a href="https://dev.realworldocaml.org/first-class-modules.html" rel="noopener noreferrer"&gt;first-class modules&lt;/a&gt;) which actually does much of the heavy lifting. Altough the include gets a bit convoluted it means that the same module is a component now (it even responds to Component.Sig the interface to components). Here, you can see the functions that our new modules have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nc"&gt;Sig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sig&lt;/span&gt;
    &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;

    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;fold&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;'&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;iter&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;get_opt&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="n"&gt;option&lt;/span&gt;
    &lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;unit&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Systems
&lt;/h2&gt;

&lt;p&gt;In order to render the sprite we need to get info from both of those components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Rendering&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;on_process&lt;/span&gt; &lt;span class="n"&gt;_key&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;spr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;draw_texture&lt;/span&gt; &lt;span class="n"&gt;spr&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;

  &lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;System2R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;on_process&lt;/span&gt; &lt;span class="nn"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;Sprite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_opt&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, I'm using first-class modules to fill in all the boilerplate and make us fill like we are working with just one instance (easier to think about too 😚️).&lt;/p&gt;

&lt;p&gt;What happens if some entity lacks either &lt;em&gt;Position&lt;/em&gt; or &lt;em&gt;Sprite&lt;/em&gt; that entity will be ignored and nothing will be rendered for it.&lt;/p&gt;

&lt;p&gt;Actually, my &lt;em&gt;Component&lt;/em&gt; system is quite basic, and I'm ignoring things like hierachies, incredibily useful for position where something will always be at an offset of something else (like a sword a character is carraying and swinging around).&lt;/p&gt;

&lt;h2&gt;
  
  
  Input
&lt;/h2&gt;

&lt;p&gt;An special case is &lt;em&gt;input&lt;/em&gt;. Every game has input and is the main way through which the game state changes, it also shouldn't be directly tied to keys (so that it can either be ported easily or be remapped by the player in case they want to).&lt;/p&gt;

&lt;p&gt;Here I borrowed from &lt;a href="https://en.wikipedia.org/wiki/Functional_reactive_programming" rel="noopener noreferrer"&gt;&lt;em&gt;FRP&lt;/em&gt;&lt;/a&gt; frameworks like &lt;a href="https://elm-lang.org/" rel="noopener noreferrer"&gt;&lt;em&gt;Elm&lt;/em&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Commands&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;GoUp&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;GoDown&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;GoLeft&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;GoRight&lt;/span&gt;
  &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Attack&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;

&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;Input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;InputFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The input componnent, which holds data and registers an entity as accepting input.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nc"&gt;InputHandling&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt;  
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;on_input&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nn"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;x_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;y_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GoDown&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Stdlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;y_size&lt;/span&gt;&lt;span class="p"&gt;)))}&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GoUp&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Stdlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GoLeft&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Stdlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;max&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;x_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GoRight&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Stdlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;min&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;  &lt;span class="n"&gt;x_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nc"&gt;Attack&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;by_name&lt;/span&gt; &lt;span class="s2"&gt;"Enemy"&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nn"&gt;Health&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Health&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;on_process&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt; &lt;span class="n"&gt;inp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nn"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;kb_key&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_key_pressed&lt;/span&gt; &lt;span class="n"&gt;kb_key&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt; 
          &lt;span class="nn"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;on_input&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt; 
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;inp&lt;/span&gt;

  &lt;span class="k"&gt;include&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;val&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;System2R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;create&lt;/span&gt; &lt;span class="n"&gt;on_process&lt;/span&gt; &lt;span class="nn"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;iter&lt;/span&gt; &lt;span class="nn"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_opt&lt;/span&gt; &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="p"&gt;;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;input&lt;/em&gt; system, which does all the processing, some sugar could be added to make it more amenable (maybe putting each command in a function and making on_process dissapear), but that could be added in the future. When we make an entity with input we get to link each key to each action:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;    &lt;span class="nn"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;by_name&lt;/span&gt; &lt;span class="s2"&gt;"Player"&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Sprite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Sprite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="s2"&gt;"assets/player.png"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Health&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;can_die&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Up&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GoUp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Down&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GoDown&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Left&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GoLeft&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Right&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GoRight&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Raylib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nn"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Space&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Commands&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Attack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See that the argument to &lt;code&gt;Input.s&lt;/code&gt; is an &lt;em&gt;array&lt;/em&gt; of &lt;em&gt;tuples&lt;/em&gt; with a key and what command does it execute. About the rest of the syntax we'll talk more about it in a minute.&lt;/p&gt;

&lt;p&gt;So now, we can assign each entity different keys and we can filter entities (in the &lt;code&gt;InputHandling&lt;/code&gt; system we could say the we needed another component which registered this entity as a player, for example).&lt;/p&gt;

&lt;h2&gt;
  
  
  Entities
&lt;/h2&gt;

&lt;p&gt;Thanks to the fact that now entities are nothing but an &lt;em&gt;ID&lt;/em&gt; (a number in my implementation) and everything is in the component, nothing restrains me of:&lt;/p&gt;

&lt;p&gt;a) Using OCaml's power to make a mini DSL&lt;br&gt;
b) Adding any characteristics to any entity in a super simple way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ocaml"&gt;&lt;code&gt;    &lt;span class="nn"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;by_name&lt;/span&gt; &lt;span class="s2"&gt;"Enemy"&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;384&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Sprite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Sprite&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;load&lt;/span&gt; &lt;span class="s2"&gt;"assets/enemy.png"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Health&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Enemy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="bp"&gt;()&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;Script&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;can_die&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;|&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ignore&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See? I've easily marked the entity as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Having a &lt;em&gt;position&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Rendering a &lt;em&gt;sprite&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Having &lt;em&gt;health&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Being an enemy&lt;/li&gt;
&lt;li&gt;Being able to die&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, while everything from there is easy to understand if you know that &lt;code&gt;Component.s&lt;/code&gt; is nothing more than a shortcut to set and that it returns the &lt;em&gt;ID&lt;/em&gt; to be used again later (that's why we need the ignore) the &lt;code&gt;Script&lt;/code&gt; part may be weird to you.&lt;/p&gt;

&lt;p&gt;And yes, &lt;em&gt;ECS&lt;/em&gt; has an incredible limitation, it is as verbose as it can get. A simple game with both imperative old-style direct programming and OOP-like game (with something like nodes) gets to have an order of magnitude less of lines than it's full-&lt;em&gt;ECS&lt;/em&gt; counterpart (maybe of about 200 to 400, and without taking into account all the &lt;em&gt;engine&lt;/em&gt; behind the scenes), when a lot of what you want in the game is just a one time behavior (like the UI which there's only one of which, maybe an attack, lots of small things ...) &lt;em&gt;ECS&lt;/em&gt; is just plain overkill, you need either another system or a escape hatch. &lt;/p&gt;

&lt;p&gt;My scape hatch is &lt;code&gt;Script&lt;/code&gt; a &lt;code&gt;Component&lt;/code&gt; which will trigger a function each frame (most probably it can improved and filtered for performance) but for the time being it proved a great addition (which was even better thanks to OCaml partial application).&lt;/p&gt;

&lt;p&gt;You can find the whole code here &lt;a href="https://github.com/sheosi/Ocaml2D/tree/first_iteration" rel="noopener noreferrer"&gt;https://github.com/sheosi/Ocaml2D/tree/first_iteration&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  My impressions
&lt;/h1&gt;

&lt;p&gt;This was a great project, it gave me some interesting impressions on all technologies.&lt;/p&gt;

&lt;h2&gt;
  
  
  OCaml
&lt;/h2&gt;

&lt;p&gt;In one word.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quirky&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;Don't get me wrong, it has some really strong points to it: &lt;em&gt;marlin&lt;/em&gt; (the &lt;em&gt;autocompletion&lt;/em&gt; engine) is a beast, it is fast as hell, the compiler (and the build system) is so 🔥️ blazing fast that it felt more as if I was working with an scripting language 🐍️, this makes iterating a joy. &lt;/p&gt;

&lt;p&gt;But as I hinted not so subtly earlier, the integration is ... subpar. I have only two files, everytime I modified &lt;code&gt;engine.ml&lt;/code&gt; the whole project needed to be recompiled so that the new definitions were available to &lt;em&gt;marlin&lt;/em&gt; for &lt;code&gt;main.ml&lt;/code&gt;, not just that but at first it seems that &lt;em&gt;drom&lt;/em&gt; kinda mixed versions and got a nasty error saying that I was using &lt;em&gt;OCaml&lt;/em&gt; "4.10" while the version the tools expected was "4.11", I had to clear all caches and packages storages so and upgrade to "4.11" in the project files (just upgrading the version in the files wasn't enough). This is isn't my first time dabbling with &lt;em&gt;OCaml&lt;/em&gt; either, and everytime I come seems like something new pops up (either that I have forgotten the kinda complicated set of instructions that I need to do).&lt;/p&gt;

&lt;p&gt;And finally, we have the language itself, using &lt;em&gt;VS Code&lt;/em&gt; and &lt;em&gt;OCaml&lt;/em&gt;'s plugin means having something that tells me which types have been inferred whic is 👌🏼️ just the best, but &lt;em&gt;OCaml&lt;/em&gt;'s fixation in not making it dependent on indentation means that the syntax gets weird at times (after all of this I still don't know 100% where to use &lt;code&gt;;;&lt;/code&gt; and sometimes it seems it is not needed, though that is good, actually).&lt;/p&gt;

&lt;h3&gt;
  
  
  My OCaml tips
&lt;/h3&gt;

&lt;p&gt;So, you want to give &lt;em&gt;OCaml&lt;/em&gt; a try? First, let me remind you of &lt;em&gt;F#&lt;/em&gt;, which is pretty close to &lt;em&gt;OCaml&lt;/em&gt;, is based on &lt;em&gt;.NET&lt;/em&gt; and you can mix it with &lt;em&gt;C#&lt;/em&gt; projects, which means you have a ton of libraries out there, you have a ton of documentation available (most of it with &lt;em&gt;C#&lt;/em&gt;, but with some expertise you'll be able to understand both and translate) and you'll have a better time convincing your boss to use it on work.&lt;/p&gt;

&lt;p&gt;What's worse is that one of the most compelling reasons up until now to learn &lt;em&gt;OCaml&lt;/em&gt;, &lt;em&gt;Reason&lt;/em&gt;, has now transformed into &lt;em&gt;ReScript&lt;/em&gt; and most definetely they see like they want to get rid of &lt;em&gt;OCaml&lt;/em&gt; from it. That sucks.&lt;/p&gt;

&lt;p&gt;But this language is still something to see by yourself, and learning functors made my head go...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b8i8jevi3frmmsdhc59.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5b8i8jevi3frmmsdhc59.gif" alt="head go boom"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you still feel like giving OCaml a try then here are some resources and tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OCaml guide&lt;/strong&gt;: &lt;a href="https://dev.realworldocaml.org/" rel="noopener noreferrer"&gt;https://dev.realworldocaml.org/&lt;/a&gt; -&amp;gt; 🎊️ Hands-down best resource to learn OCaml structures&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IDE&lt;/strong&gt;: &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt; + &lt;a href="https://github.com/ocamllabs/vscode-ocaml-platform" rel="noopener noreferrer"&gt;OCaml Platform&lt;/a&gt; -&amp;gt; There used to be several plugins (including the one from &lt;em&gt;Reason&lt;/em&gt;) but nowadays the best is this one, made by the OCaml Platform itself (a group making OCaml more amenable)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Standard library&lt;/strong&gt;: &lt;a href="https://ocaml-batteries-team.github.io/batteries-included/hdoc2/" rel="noopener noreferrer"&gt;Batteries&lt;/a&gt; or Jane Street's &lt;a href="https://opensource.janestreet.com/core/" rel="noopener noreferrer"&gt;Core&lt;/a&gt;: You know that &lt;em&gt;OCaml&lt;/em&gt;'s standard library is a bit... 😑️ lacking, and old, so there are several attempts to replace it. On the one hand you have the battle-proven &lt;em&gt;Core&lt;/em&gt; by the folks on Jane Street, a big brand using exclusively OCaml but is incompatible with OCaml's standard library and the other hand you have &lt;em&gt;Batteries&lt;/em&gt; a community effort pretending to extend OCaml's standard library.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  ECS
&lt;/h2&gt;

&lt;p&gt;Finally, I understand what I've read about using &lt;em&gt;ECS&lt;/em&gt;. While it feels awesome defining an entity and giving it any property I feel like, trying to implement the a small label that showed our health (and another for the enemy) meant that I needed to make a &lt;code&gt;Component&lt;/code&gt; and a &lt;code&gt;System&lt;/code&gt; just for that, at that time I understood that trying to shove everything inside the &lt;em&gt;ECS&lt;/em&gt; is going to make your code &lt;em&gt;verbose&lt;/em&gt; as hell and you may end with several times the number of lines you might had otherwise.&lt;/p&gt;

&lt;p&gt;In my case, I made the &lt;code&gt;Script&lt;/code&gt; Component as an escape hatch, and honestly it felt 😀️ good. &lt;em&gt;OCaml&lt;/em&gt;'s partially applied functions really helped too. Honestly, I can see this design getting some sugar and being used more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functional programming
&lt;/h2&gt;

&lt;p&gt;The code here is not super functional, I acknowledge that, yet the part where it is more functional, that is the &lt;code&gt;Input&lt;/code&gt;, while still verbose feels pretty good, the &lt;code&gt;Command&lt;/code&gt; idea taken from &lt;em&gt;FRP&lt;/em&gt; and &lt;em&gt;Elm&lt;/em&gt; is a great way of abstracting input hardware.&lt;/p&gt;

&lt;p&gt;But I can see shoving everything inside like an object called &lt;code&gt;World&lt;/code&gt; and passing that down on all functions for them to do wathever they feel like, something like what the &lt;a href="https://github.com/bryanedds/Nu" rel="noopener noreferrer"&gt;&lt;em&gt;Nu&lt;/em&gt; game engine&lt;/a&gt; does.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raylib
&lt;/h2&gt;

&lt;p&gt;If I take something really good from here is &lt;em&gt;Raylib&lt;/em&gt;. As I said you can use &lt;em&gt;Raylib&lt;/em&gt; pretty much wherever you use &lt;em&gt;SDL&lt;/em&gt;, but is really easy, with functions with understandable names, modern and easy-to-parse web with tons and tons of examples. But what does it have? Well, in &lt;em&gt;Raylib&lt;/em&gt; you'll find: 3d (with it's own abstraction layer), audio (no 3d audio, but it does support streaming), physics, texts, 2d, GUI and even networking seems to be on the works: &lt;a href="https://github.com/raysan5/raylib/issues/753" rel="noopener noreferrer"&gt;https://github.com/raysan5/raylib/issues/753&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basically, is an engine but as a library.&lt;/p&gt;

&lt;p&gt;My only gripe is that the 3d part lacks Vulkan, and while &lt;em&gt;raysan5&lt;/em&gt; (the person behind &lt;em&gt;Raylib&lt;/em&gt;) is not against it, does not have a lot interest in it.&lt;/p&gt;

&lt;p&gt;I would take &lt;em&gt;raylib&lt;/em&gt; for a ride if your project needs low-level control.&lt;/p&gt;

&lt;h1&gt;
  
  
  Final thoughts
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; &lt;em&gt;ECS&lt;/em&gt; is good but tedious and verbose, &lt;em&gt;OCaml&lt;/em&gt; is quirky but with people putting some real effort on it, and &lt;em&gt;raylib&lt;/em&gt; has chances of becoming my go-to low level game lib.&lt;/p&gt;

&lt;p&gt;I might further develop this architecture on the future, most probably not to use it by itself, but as research and to port it to other frameworks later. &lt;/p&gt;

&lt;p&gt;Some frameworks that I'm interested in and that I might test are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.rust-lang.org/" rel="noopener noreferrer"&gt;Rust&lt;/a&gt; + &lt;a href="https://bevyengine.org/" rel="noopener noreferrer"&gt;Bevy&lt;/a&gt; + maybe? &lt;a href="https://github.com/gluon-lang/gluon" rel="noopener noreferrer"&gt;gluon&lt;/a&gt; (An ML for Rust)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fsharp.org/" rel="noopener noreferrer"&gt;F#&lt;/a&gt; + &lt;a href="https://www.monogame.net/" rel="noopener noreferrer"&gt;monogame&lt;/a&gt; or &lt;a href="https://www.raylib.com/examples.html" rel="noopener noreferrer"&gt;raylib&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fsharp.org/" rel="noopener noreferrer"&gt;F#&lt;/a&gt; + &lt;a href="https://godotengine.org/" rel="noopener noreferrer"&gt;godot&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Maybe &lt;a href="https://swift.org/" rel="noopener noreferrer"&gt;Swift&lt;/a&gt;...?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have had experiences on those, let me know in the comment. Also, have you had any experience on functional games and/or &lt;em&gt;ECS&lt;/em&gt;?&lt;/p&gt;

&lt;h1&gt;
  
  
  Links
&lt;/h1&gt;

&lt;p&gt;I based my &lt;em&gt;ECS&lt;/em&gt; design on this: &lt;a href="https://cranialburnout.blogspot.com/2013/09/database-radiation-hazard.html" rel="noopener noreferrer"&gt;https://cranialburnout.blogspot.com/2013/09/database-radiation-hazard.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ocaml</category>
      <category>gamedev</category>
      <category>functional</category>
    </item>
  </channel>
</rss>
