Salience As A Routing Tool

Posted On: 2020-12-14

By Mark

The Salience Engine is a tool I've developed for myself, to help me with writing and organizing my current project. Based on the feedback I've received about it, however, I'm not sure I've been clear about why it's important. At its heart, the Salience Engine is intended to solve one specific problem: that the routing of branches in a branching narrative limits the kinds of stories that can be reasonably told.

The Hub Of Hubs Problem

In a previous post about the Salience Engine, I described it as a solution to the "Hub of Hubs" problem. That problem, to put it succinctly, is that the branching narrative tool I use* requires too much code for its routing. For each new layer of routing, the amount of possibilities increases exponentially, and all routing must be coded imperatively, explicitly telling the system where to go and what to do.

Limited Salience

To combat this, I implemented the Salience Engine so that it uses a declarative programming style: each element describes what makes it salient, rather than telling the system what to do. From that, the engine infers which element to use for further processing. While this approach was loosely based on how a rules engine works, it is (deliberately) much simpler - to avoid many of the pitfalls rules engines face.

Using a declarative approach for the Salience Engine had two key risks:

  1. Proliferation of intermediary state: many declarative systems use state to control code flow, which often necessitates the creation of a large number of intermediary states
  2. Overwhelming complexity: many declarative systems modify their underlying state. If that state is immediately fed back into the system, that is forward chaining, which is powerful in ways that can make it extremely hard to debug
Both of these problems are caused by modifying state, so I deliberately omitted that ability from the Salience Engine. Instead, the Salience Engine is designed to live inside another imperative system: some code calls into the Salience Engine, and the Salience Engine will return a result - with no state changes and no chaining.

Salience As Routing Alone

Although the Salience Engine is technically agnostic about what it returns, in my current project it only ever returns Yarn Spinner nodes. This limits it to only solve problems of routing, and leaves untapped a wealth of other possible use cases. Personally, I think this is good thing: a lot of the potential use-cases are nice for adding texture*, but could wind up being distracting from the task of making narrative content. Thus, keeping the tool focused will help keep me focused.

Key Benefits

Armed with salience-based routing, I can avoid the many of the pitfalls of the Hub of Hubs problem. The complexity of the routing is now linear - making all additions and revisions equally simple. New content can be added incrementally, without having to rework the routing on any of the old content. Using sane defaults for salient routing means that the dialogue will remain sane, even if the game state goes off the rails. Lastly, and perhaps most importantly, switching between salience-based and normal branching is trivial - so the right one can always be used, rather than being locked into one or the other by external factors.


Hopefully this has improved your understanding of the Salience Engine, and how it's helping me to write a story that might otherwise be too complex and interconnected to maintain. As always, if you have any thoughts or feedback, please let me know.