Adam Gray

Blog
07/25/2023

Fibers v1

I’ve been a long time fan of Workflowy, something about an outliner tool really suits my way of thinking.

I wanted to understand how they built the application. To do so, I created my own version of the tool using ReactJS.

Specifically, I used a reverse linked list as the main data structure for the nodes (or “fibers” as I ended up calling them!). In other implementations of workflowy clones I noticed that people stored data as a nested JSON array. When I attempted this implementation it inherently required recursive traversal down to the node that required updating.

Instead, with a reverse linked list I was able to keep nesting to a minimum and quickly access the required element with each element only needing to track it’s most immediate sibling, and parent. I built this version of the application using Test Driven Development as I needed to ensure all adjustments were correct.

I made extensive use of this freeform board to test the implementation. Nodes can be tough to keep track of!

Fibers in Freeform

This work culminated in what I can describe as a pretty useful, offline rendition off Workflowy!

fibers.app

However, I didn’t stop here. At least, I should have. I wanted to dive deeper into workflowy itself to understand how it actually worked. Not how I thought it worked.

I spent quite some time disecting the innards of Workflowy and discovered some very interesting things.

Firstly, unlike Fibers which used React as the rendering engine. Workflowy has their own custom rendering engine that directly manipulates DOM nodes. They work on the principal of delta changes where updates are send to the server in small JSON-like blobs that partially update the DOM. Essentially they broadcast iterative changes to the server to keep everything in sync.

This knowledge led me down a rabbit hole that brought me to Lexical.dev I attempted to build my own workflowy tool using lexical as the rendering engine. However during my experimentation I noticed an issue with their implementation of TabIndentation in the docs so I filed an issue The solution for TabIndentation was not super effective in ensuring that the rules of a node-based workflowy tool were respected. At this point I left the v2 of Fibers on the drawing board for a bit.

Fibers is an on-going passion project that started as a nice tool built in React, and has led to the deeper workings of DOM APIs, considerations of implementing a Text Rendering Engine from scratch with canvas (maybe even emscripten to compile down to webassembly). However at this point, I really like the functionality of Fibers, and have more questions to answer elsewhere!