Programmable Ink Lab Notes
title
Portemine
dated
Q1 2026
author
Marcel Goethals

The goal of this study is exploring the use of propagator networks as the computational model for Playbook. The question of a computational model has been a long-standing one for the ink track, and different projects have explored different options.

Around the time of Habitat, we came to the conclusion that there is no single programming model that would be a great fit for all the different use cases we have in mind, and that we would need to support multiple models. I don’t think we’ve ever found a satisfying answer to this question, and it’s something we’ve been circling around ever since.

My hunch is that propagator networks might be a possible answer for a few reasons.

  1. There’s a simple visual mapping for propagator networks, which means we can construct programs in user space without needing to fall back on text.
  2. It seems general enough to act as a kind of “glue” that would allow us to combine very different kinds of semantics, like reactive dataflow, bidirectional flow, constraint solving, rewriting, or even more “imperative” styles of programming.
  3. I imagine this would act like a kind of “assembly language” for Playbook, that we could build other “visual languages” on top of in user space. For example, I imagine TrapDoor-like semantics could be implemented using this under the hood.
  4. I suspect there’s an angle here that would trivially allow us to support distributed execution across different devices, “a local first vm”.

19 Feb 2026

Here’s an example of a simple Celsius-to-Fahrenheit temperature converter in this style.

Interactive Demo (shift+drag to scrub numbers)

In this system we explicitly model time as a global monotonically increasing timestamp. Each time the user scrubs a number, the global timer goes up. Whenever we update a cell we also tag it with the current timestamp (shown as the small grey number in the corner). This is how we can support cycles without getting into infinite loops; Propagators simply compare the timestamp of all the cells it’s connected to. If on cell is newer than the others, then it processes the update and sends out new updates with a newer timestamp. This means cells can never be updated more than once per tick.

This approach allows the user to construct flows that behave very differently in different directions (Which I imagine can be both very useful, and a massive footgun).