'Draftback' for Bike outlining?

While thinking and writing (about interactions between writing and thinking),
and using a draft Bike extension to visualise both dependency graphs (clarifications and moves to persuade etc) and the narrative paths that are taken through those graphs,

I soon realise that the missing component is time – the particular sequences in which thoughts and texts are reshaped.

This reminds me of the Draftback Chrome extension, which has been around for a while now, finding various uses, and provoking various thoughts.

(It lets you watch the history of a text as a kind of editing-sequence movie).


An outlining analogue of Draftback, recording the growth and reshaping of trees (or forests) of thought, rather than sequences of text, might, I think, be even more interesting.

Might anyone else be interested in experimenting with such a thing ?

I haven’t yet tried, but it looks as if the Bike 2.0 Preview extension kit API’s Outline.observeChanges, and the associated OutlineChange and RowChange, types might already enable this kind of thing.

As for storing a replayable sequence of events, perhaps an sqlite database ?


Etherpad change-sets seem to be another model:

1 Like

I don’t know if this is the way I’ll end up going, but it’s been the plan for a while now:

Bike iOS I need some sort of sync system. Automerge style CRDT’s seems like a good solution for Bike, because no server is needed. They support realtime sync, but that’s not so interesting for me, the nicer part is they also support offline sync with no serve.

To implement that each peer stores a heavily optimized list of all previous operations. So besides syncing, they allow you to reconstruct your document at various points in history, which I think is exactly what you are after.

Again, I’m not sure I’ll go in this direction, performance has been an issue in the past when I experimented with these systems, but the latest generation is supposed to be much faster.

Assuming I went in this direction then I think it would be pretty simple to provide an API for outline history.


I’ll start thinking about this in more detail soon, post 2.0 release, once I start iOS work.

1 Like

Actually just had another thought. If you did want to experiment in this direction without having to wait for me I think the CLI would be a good way to do it.

Create your own app CLI, pipe bike observe into it, and then you can process those changes. Experimenting with serializing into SQLITE, Automerge, Loro. See what works best.

Currently Bike’s cli only offers bike observe outline and bike observe outline rows, but I can also add bike observe outline changes if you want to go in this direction.

1 Like

That sounds very good, if you do find the time. I’d like to start some some simple experiments of that kind here, to see if I can at least record and animate a few illustrative examples.

( and I very much look forward to seeing how your experiments and thoughts with syncing and conflict-free replicated data types for outlines develop – that sounds very interesting … )


Thank you for the pointers to Automerge and Loro CRDT too !

(Loro looks quite well-adapted to edits of tree-shaped data …)

The latest release provides bike observe outline changes which then streams incremental changes, I think suitable for experimenting with these ideas. Let me know if you make progress, needed changes, etc.

2 Likes

wonderful – thank you !
:folded_hands:

The .ndjson change stream is excellent …

On cross-session tracking, my understanding is that that we get a .persistentId by default for the document, while rows (understandably) have only .id by default.

This works fine for recording within a given editing session, but I think I may need to ensure that all (new and existing) rows somehow get a .persistentId if I want to track a particular document across different editing sessions.


What might be the most solid approach – in this context – of ensuring that newly-created rows always get a .persistentId ?

Does it look feasible to design a switch for that on the bike command,
or should I, perhaps, really handle it separately – for example, with a dedicated extension observing outline changes ?

Good question, and I’m not sure, but I think trying to use Bike’s persistentIds isn’t the right approach.

Instead I would just assume that you are in full control of both the outline state and crdt state and use session.ids to map between the two (in a runtime structure, don’t try to persist this mapping).

The problem case happens after you have closed outline and need to open it, but again I would assume that you are always in full sync with crdt. That means when you first open the outline you can iterate through rows in order in both bike outline and crdt structure and setup a new runtime map from session.id to crdt.id. Since the are in sync it should work.

And if you want to get fancier and handle cases where they are no longer in sync you could do some sort of diff and repair the session.id : crdt.id map/structures that way?

I’m not sure, but I think that would work?

1 Like