SPINE

Spine is a prototype of a software architecture that enables direct manipulation while remaining live and editable. It’s a declarative push-based reactive system, enabling incremental computation.

It’s incomplete, buggy and poorly written.

(Presentation for LIVE 2025 with additional examples)

Examples

Spine supports multi-touch.

Note: Not not all examples are well-behaved, and might start breaking when you edit. You might be able to refresh the browser to continue.

Examples

Examples from LIVE 2025 presentation

Other examples:

What and Why

(Simplified glossary of the fancy terms)

Parser

The parser is inspired by JSON and designed to have a generic and loose syntax. It leaves validation / interpretation up to the next abstraction level. Like in CoffeeScript, argument parenthesis can be omitted. Like Lua, there is a single a container structure, supporting order and optional keys. Brackets () [] {}, all have the same behaviour, except () for items <= 1, which are special to support infix notation etc.

Syntax Experiments

Spine syntax is mainly inspired by lua and js, but there are some more experimental stuff as well. For instance, a map function which is implemented in way that it takes its arguments as code, this way you don’t have to wrap the expression in a function:

map x = [1,2,3], x * x  // square a list

map is also available as an operator (then always using x)

[1,2,3] -> x * x

If the right side is a single token, x is automatically injected as an argument, so

[1,2,3] -> sin -> x * 10 -> floor

means:

[1,2,3] -> sin(x) -> x * 10 -> floor(x)

It also works on single values:

0.7 -> sin -> x * 10 -> floor  

Note that most operators work recursively on arrays

Comparison: Lua / js vs Spine

Lua / js Spine impl
Value untyped value
reactiveValue

untyped value wrapped
in reactive container
create() get() set()
Combined
Array / Dict
table / object*

{}
.insert() / .push()*
- / .map()*
reactiveArray

raCreate()
raInsert()
raMap()
Parse load() / new Functor() parseToAST()
“Runnable” function AST (js object)
“Run” () instantiateRec()

returns live instance handle AND reactiveValue
“State” Call Stack

Contains local data for currently
running function calls
Block Tree

Contains everything
that is instantiated
* js don't have a combined object/array

Source Code

Source needs serious overhaul or a complete rewrite.

These links are to old revisions:

Spine was written in a weird transpiler language, however it outputs somewhat readable js. So, if you prefer, you could read the transpiled code, search for '*' or spineComp_if or similar. You can run the transpiler environment live (development mode)

I’ve started rewriting parts of the code in C# for my demoscene projects, however I did not really do much bidirectional stuff yet.

Options

Missing / Unsolved