krestianstvo-renkon
v0.1.5
Published
Croquet-TeaTime-inspired, Renkon-driven collaborative computational engine
Maintainers
Readme
Krestianstvo - Renkon | Pure FRP Croquet VM
Introducing the Croquet-TeaTime-inspired, Renkon-driven collaborative computational engine (WIP)
Live demo (https://renkon.krestianstvo.org)

- Overall all parts of the classic Croquet VM are implemented, including Reflector server, Virtual Time, Recursive Future Messages, Portals etc. all in Renkon FRP architecture.
- Internal dispatcher of messages queue of the VM is implemented with recursive causality drain, that properly handles nested message future sends.
- Portals, Recursive spawning and Parallelising "sheaf of sheaves of VMs" running in form of Renkon signals
- No dependencies - works directly in browser or NodeJS
- Snapshot/Restoring logic - late joiners get full state + history replay
- Krestianify compiller converts a unified Renkon app (single source string) into the model/view split that KrestianstvoVM.start() expects.
- Distributing as an ES6 module
Source files
Pure FRP Croquet VM
The Recursive Causality Engine is the implmentation in Renkon of the Croquet VM's core in pure FRP.
worldState is a Behaviors.collect node that is both accumulator and its own trigger:
const worldState = Behaviors.collect(
{ ...initialState },
Events.or(incoming, Events.change($worldState)),
(state, ev) => {
// ev is either a new incoming message (enqueue path)
// or a self-triggered drain signal (drain path)
if (ev.time !== undefined && ev.queue !== undefined) {
const drained = _drain(state);
return drained === state ? state : drained; // same ref = stop
}
return _enqueue(state, ev);
}
);The self-referential loop drives drain recursion without any explicit JS loop:
- Heartbeat arrives →
_enqueueadvancesworldState.time Events.change($worldState)fires →_drainchecks the queue- A message is ready at current virtual time →
applyActionruns → newworldState - The new
worldStatetriggers itself again →_drainrecurses - Queue empty →
_drainreturns same reference → loop breaks
This gives sub-tick ordering — multiple messages at the same virtual time are processed in sequence within a single real-time frame.

Documentation
Learn more about
Simple app
Import Krestianstvo VM as ES6 Module. No build step. No npm install.
<!DOCTYPE html>
<div id="root"></div>
<script type="module">
import { selo } from 'https://cdn.jsdelivr.net/npm/krestianstvo-renkon@latest/public/index.js';
const APP = `
// ── MODEL ──
const counter = Behaviors.collect(0, click,
(prev, _) => prev + 1);
// ── VIEW ───
const click = Events.listener(rootEl.querySelector('#btn'), 'click',
() => 1);
const _render = (()=>{
rootEl.querySelector('#count').textContent = counter;
})();
`;
const buildUI = (rootEl, label) => {
rootEl.innerHTML = `
<div>${label}</div>
<div id="count">0</div>
<button id="btn">Click me</button>
`;
};
selo({
app: APP,
modelNodes: ['counter'],
seloId: 'my-app',
reflector: 'ws://localhost:3000',
rootEl: document.getElementById('root'),
buildUI,
});
</script>
To run reflector localy
npm install
npm startOpen web browser:
http://localhost:3000 - list demo apps.
URL params for demo page:
- ?k=seloName — selo id
- ?r=http://host:port — reflector base url
