Dev Blog 12: Threads

Yesterday and today have been dedicated to a big push on Threads, which are the Davenport equivalent of connectors in a flow-chart.

I was able to salvage a little of the code from the earlier prototype and hook it into the new renderer without too much fuss. But the visual aspect of Threads is just the tip of the iceberg.

As I've mentioned elsewhere, Davenport supports time-stamping notes so that you can relate them to particular moments in your story. This helps LISA bring you the most relevant information as you're working.

A planned feature for Threads was that they should automatically propagate time-stamping between connected notes. So if you have a scene-note with a time-stamp, and you create another note nearby connected by a thread, LISA would understand that information relevant to the scene's moment in the timeline is also probably the most relevant when you're working on the connected idea.

That much is really straightforward. But what happens if I do this:

I thought it would be really neat if LISA used the times of the top and bottom notes, and the relative distance from each of them, to estimate the time-stamp of the middle note. Move it up, the time gets earlier. Move it down, the time gets later. And I wanted it to work however many notes you string between two endpoints.

This proved a little trickier, but by broadcasting timestamps out along threads, measuring distance travelled and averaging the results, I got it working. That was about five hours ago, which was when I realised this threw a massive spanner in the works:


The problem here is that "What time is it?" is, by my guess, three times further from the bottom note than the top one. So its time stamp will be around 2pm.

However, the total distance along threads from "Dinner" to "Bollocks" is only slightly further than "Lunch" to "Bollocks". That big long thread sticking out to the side ends up dominating the maths, which means that "Bollocks" gets a time stamp much closer to 3pm. And that's not what you would expect. You would expect something connected only to the middle note to inherit its timestamp unchanged.

This creates a rather nasty problem which this next example illustrates:

If "Lunch" and "Dinner" each broadcast their times as far as they'll go in turn, we get the intuitively wrong result from the earlier example. But if we only let the times spread one link at a time, then 'Lunch's time gets to 'Bollocks' before 'Mr Wolf' knows about 'Dinner'. So Mr Wolf has to say "Sorry, sorry, I meant this is the time - which is a nightmare if that time has already been averaged into time-stamps further out in the network.

That was a real head-scratcher, especially as I wanted this to be fast enough for you to be able to drag notes around and see the times change smoothly, even in a large document with lots of connections.

The solution I've found was quite satisfying, in the end:

  1. Every note with its own time stamp gets added to a working list with a tally of 1.
  2. Work through the list, broadcasting time-stamps out across the network.
  3. Any note that finds itself trying to broadcast to a 'tally-1' note tags itself as 'tally-2', calculates its timestamp, and adds itself to the end of the working list.
  4. When you reach the 'tally-2' notes in the list, start tagging their neighbours as 'tally-3'
  5. Keep going until the list is empty.
Imagine waves washing back and forth across the network, depositing 'finished' notes each time they hit the shores, which brings the shorelines closer and closer together until there's no more water. Each note only has to do its broadcasting once, only needs to calculate its timestamp once, and you never have to unpick anything you've already done.

Comments

Popular Posts