OCaml Weekly News
Hello
Here is the latest OCaml Weekly News, for the week of September 22 to 29, 2026.
Table of Contents
2nd release elm_playground (a game engine for beginners)
Archive: https://discuss.ocaml.org/t/ann-2nd-release-elm-playground-a-game-engine-for-beginners/18552/1
Yoann Padioleau announced
It is my pleasure, again, to announce the second release of elm_playground, an OCaml package that allows you to easily create pictures, animations, and even video games in a portable way using an API that really simplifies how to view the computer and its devices (the screen, keyboard, and mouse). The library offers a native backend to run the games from a terminal and a web backend to run the games in your browser.
This is a port of the excellent Elm playground package https://github.com/evancz/elm-playground to OCaml.
You can install it via OPAM via
opam install elm_playground; opam install elm_playground_native.
The main changes are most of the bugs in the first release have been fixed (mostly by Claude Code), and that now the native and web backend are fully working on all the examples and games. Here is for instance how to play Tetris compiled by jsoo:
https://aryx.github.io/ocaml-elm-playground/games/Tetris.html
Here are a few examples of code using the library.
First a “picture” app:
(* from https://elm-lang.org/examples/picture *)
open Playground
let app =
picture [
rectangle brown 40. 200.
|> move_down 80.;
circle green 100.
|> move_up 100.;
]
let main = Playground_platform.run_app app
Then an “animation” app:
(* from https://elm-lang.org/examples/animation *)
open Playground
let view time = [
octagon darkGray 36.
|> move_left 100.
|> rotate (spin 3. time);
octagon darkGray 36.
|> move_right 100.
|> rotate (spin 3. time);
rectangle red 300. 80.
|> move_up (wave 50. 54. 2. time)
|> rotate (zigzag (-. 2.) 2. 8. time);
]
let app =
animation view
let main = Playground_platform.run_app app
And finally a “game” app:
(* from https://elm-lang.org/examples/mouse *)
open Playground
let view _computer (x, y) = [
square blue 40.
|> move x y
]
let update computer (x, y) =
(x +. to_x computer.keyboard, y +. to_y computer.keyboard)
let app =
game view update (0., 0.)
let main = Playground_platform.run_app app
Note that you can write more complex games. For example here is a screenshot of a toy tetris app:
For more information, follow the README at https://github.com/aryx/ocaml-elm-playground
See also the code of some classic examples and try them online thx to jsoo: https://aryx.github.io/ocaml-elm-playground/games/
moonpool 0.12
Simon Cruanes announced
Howdy, I just released moonpool 0.12, now coming to an opam repository near you.
Moonpool (first announced here) is a threadpool library for OCaml 5, leveraging domains to actually go brrrrrrr on multiple cores. The (still unique‽) design of moonpool allows the user to create multiple pools, whose cumulative size exceeds Domain.recommended_domain_count() without slowdown. It does that by using… threads… instead of domains. Yep.
Anyway there's a whole bunch of bugfixes (including one to correct pathological memory usage in #45, big up @gasche as usual :heart_hands:), support for ambient-context, some cleanup, dscheck for tests, etc.
Cheerios on you and your cereal bowls
tw 1.1.0, Tailwind CSS in OCaml
Thomas Gazagnaire announced
I am happy to announce the release of tw 1.1.0 (available on brew already and soon in opam).
$ brew install samoht/tap/tw $ opam install tw.1.1.0
tw is an implementation of Tailwind CSS v4 in pure OCaml. This is the first version I would advise people to use: the previous ones only partially supported some features, and it was unclear where things were breaking. The 1.1.0 release now covers all the Tailwind v4 utilities, variants and official plugins, and more importantly it comes with a proper, mechanical way to check that its output has no visual difference from Tailwind's.
tw now comes with a CLI that is a drop-in replacement for the Tailwind CLI. It builds whole Tailwind projects from their CSS entrypoint (tw -i src/app.css -o dist/app.css), including @theme, @source, @apply, custom utilities and variants, and the typography and forms plugins, without Node.js. It works for any project configured in CSS, whatever language generates the HTML.
If you are using OCaml you can directly use an OCaml API with Tw_html that lets you build HTML components carrying their own styles. It exposes htmlit's API but attaches tw classes to every node so you can query what CSS a given HTML fragment needs to be displayed.
You can read more about the process to get to this release in my blog post. Feedback greatly appreciated in the issue tracker or in DMs!
Cascade: A Typed CSS Toolkit in OCaml
Continuing this thread, Thomas Gazagnaire announced
I am happy to announce the release of cascade 1.2.1 in opam and Homebrew. It mostly contains (many) bug fixes, a lot of them found by rendering stylesheets in headless Chrome and comparing the pixels.
If you shipped minified CSS built with 1.1.0, please regenerate it and check the difference:
$ cascade diff --diff=canonical old.css new.css
If you want to check pixel-level differences of the rendering on a given page, you can now use:
$ cascade diff --browser --html page.html a.css b.css
This new command helped to identify and fix numerous issues; hence the (way too long) list of fixes in CHANGES.md.
ppx_deriving_{yaml,ezjsonm,yamlx} 0.5.0
Patrick Ferris announced
Hello!
I'm happy to announce the release of ppx_deriving_yaml and ppx_deriving_ezjsonm version 0.5.0 alongside the first release of ppx_deriving_yamlx which uses YAMLx as a backend (thank you to @raphael-proust and @mjambon for their work and input). All three derivers use the same core codec with each specialising to their particular representation.
This release also contains a bug fix for deriving _ array types which was completely broken (so broken, your code wouldn't compile).
Installing
opam update opam install ppx_deriving_yaml opam install ppx_deriving_ezjsonm opam install ppx_deriving_yamlx
Documentation
Please find the documentation on ocaml.org, for example docs for ppx_deriving_yamlx.
Happy deriving :two_hump_camel:
kqueue-ml 0.5.0
Continuing this thread, Anurag Soni announced
I've published a couple of new releases since 0.5.
- Added support for
EVFILT_USERandEVFILT_SIGNAL - Change the interface for registering events to avoid needing to allocate a record
The new update can be found on opam
Windtrap: one library for all your OCaml tests
Thibaut Mattio announced
Hi everyone!
I'm happy to announce the release of Windtrap, a testing framework for OCaml that brings the different testing methods of the ecosystem into one library:
- Unit tests, with an Alcotest-like API.
- Expect and snapshot tests, with a companion PPX compatible with
ppx_expectandppx_inline_test, but usable without it. - Property tests as seen in QCheck, with a library of textbook laws (round trips, orders, associativity, and more).
- Stateful and differential tests, as seen in qcheck-stm and Monolith, on one domain or several.
- Test coverage (as with Bisect_ppx) and mutation testing (as with mutaml).
Every kind of test composes with the others into one suite and one output, and the library has no dependencies beyond OCaml (the optional PPX uses ppxlib).
Here's a small suite that tests the standard library with a unit test, a property stated as a textbook law, and a stateful test of Stack against a list:
open Windtrap
(* A reference for Stack: a list, its top first. *)
module Model = struct
type t = int list ref
let create () = ref []
let push x m = m := x :: !m
let length m = List.length !m
let pop m =
match !m with
| [] -> raise Stack.Empty
| x :: rest ->
m := rest;
x
end
let stack = abstract "s" ~pp:(fun ppf m -> Testable.pp (list int) ppf !m)
let lists =
group "list"
[
test "rev reverses a list" (fun () ->
equal (list int) [ 3; 2; 1 ] (List.rev [ 1; 2; 3 ]));
prop "rev is an involution" (Gen.list Gen.int)
(Law.involutive (list int) List.rev);
]
let stacks =
group "stack"
[
stateful "behaves like a list"
[
command "create" (Gen.unit @-> makes stack) Model.create Stack.create;
command "push"
(Gen.int @-> stack ^-> returns unit)
Model.push Stack.push;
command "pop" (stack ^-> returns int) Model.pop Stack.pop;
command "length" (stack ^-> returns int) Model.length Stack.length;
];
]
let () = exit (run "stdlib" [ lists; stacks ])
We built Windtrap at Invariant as part of our work on making code written by agents more trustworthy. Agents replicate what they find in a repository, so a project full of strong tests gets more of them. Windtrap comes with an agent skill that guides agents towards the right kind of test, but we care just as much about humans, and put a lot of effort into making the API and output ergonomic and delightful.
You can read more about it in the announcement post. It walks through an example suite, what a failure looks like, coverage and mutation testing, and an experiment where we used Windtrap to test the OCaml standard library.
To install it (when the PR is merged on opam-repository):
opam install windtrap ppx_windtrap
The manual (written by agents with my guidance, I hope you'll find the writing voice bearable, but if enough people complain I'll look into rewriting it by hand) has one page per kind of test. Feedback is very welcome, here or on the issue tracker.
Happy hacking!
—
Acknowledgments
Windtrap builds on ideas and code from several OCaml projects:
- Alcotest by Thomas Gazagnaire: test structure and runner design.
- Craig Ferguson's Alcotest PRs (#294, #247): API design, subcomponent diffing.
- QCheck2 by Simon Cruanes et al.: generator design and integrated shrinking.
- Monolith by François Pottier, and qcheck-stm by Jan Midtgaard et al.: stateful testing against a reference, on one domain or several.
- ppx_expect and ppx_inline_test by Jane Street: expect test paradigm and dune integration, and ppx_expect's test corpus.
- Bisect_ppx by Anton Bachin et al.: coverage instrumentation and runtime.
- mutaml by Jan Midtgaard: mutation testing for OCaml as a PPX.
- mtime by Daniel Bünzli: the monotonic clock.
Ocsigen Server 8.0.0
Vincent Balat announced
Hi everyone!
Ocsigen Server 8.0.0 is out, the web server written in OCaml, usable as an executable or as a library. Some highlights:
- One command, no config file:
ocsigenserver ./publicserves a directory, andocsigenserver --reverse-proxy http://localhost:9000puts a proxy in front of your app, with compression and security headers already on. - Static files now answer conditional requests (ETag, 304) and byte ranges, so seeking in a video or resuming a download just works.
- zstd compression, on a new bytesrw backend.
- A new Securityheaders extension.
- Access logs in the standard Combined Log Format, readable by the usual tools.
- The public modules were renamed (
Ocsigen.Server,Ocsigen.Config, …). The newocsigenserver-compatpackage keeps the old names, so existing code still builds.
opam install ocsigenserver
A release of Eliom and other projects compatible with this version will follow in a few weeks.
All the details are in the blog post: https://ocsigen.org/blog/posts/ocsigenserver-8.0.0.html
Old CWN
If you happen to miss a CWN, you can send me a message and I'll mail it to you, or go take a look at the archive or the RSS feed of the archives.
If you also wish to receive it every week by mail, you may subscribe to the caml-list.