Laminar Notes
I've always been dissatisfied with the various note-taking software, outliners, mind-mappers, and other tools for keeping track of ones ideas. They felt too restrictive. I often come up with an idea without knowing exactly where it should fit into any existing organization structure. My (still in-progress) answer is Laminar Notes
I read Jef Raskin's The Humane Interface late in college and became enamored with the idea of a zooming user interface, one where all content notionally exists in a single 2d plane, and the user can zoom in to a particular area to focus, or zoom out for a big picture. The level of detail displayed adjusts based on the zoom level. This struck me, and mostly still strikes me, as both a very powerful and very intuitive UI metaphor.
Implementing a ZUI with web technology is tricky. Software using web technology is easier to implement, and runs on all consumer platforms. But the most natural version of the ZUI concept would require the kind of free-form graphics that you could only acheive on the web with fully custom canvas graphics. The seed of Laminar Notes, at least in its current form, was planted when I hit on the idea I call a "discrete fish-eye ZUI". When you zoom into one portion of the content, the content outside the focused region gets smaller, similar to the way things near the edge of a fisheye lens shrink. And the zooming happens in steps, one layer up or down the nesting hierarchy at a time. I realized this would be quite manageable to implement in any modern web framework.
Technical Details
The data model is a tree of "Items", JSON blobs containing mostly plain text and some metadata. The most important metadata is the parent id, but they can also have a color and layout for their child items. A simple tree of text is a surprisingly flexible model, but not a ground-breaking one. There is lots of room for expansion here.
Virtualizing items that aren't on screen, that is skipping their rendering in the DOM, turned out to be critical for performance, especially on mobile. Any zoom operation modifies every element on screen, which can cause noticeable lag after every click or tap. The virtualization subsystem must estimate or cache the size of every item at every zoom level so that it can replace those items with a simple box when they're off screen. Children of those items can then be omitted entirely, drastically cutting down the number of DOM nodes. This involved some tricky calculations and cache-invalidation logic, but the final code is nicely compact.
I picked Vue as the framework for pragmatic reasons. Reactive components are quite a nice paradigm for web apps. I had used React briefly and considered it, but Vue appeared to have learned some lessons from React's design and also has a less chaotic ecosystem.
Typescript was a similarly pragmatic choice. I knew I wanted some typing support when writing JavaScript. I seriously considered one of the OCaml-to-JavaScript compilers, but figured they would be higher-friction than Typescript, which both starts closer to JavaScript and has a well-funded ecosystem.
PouchDB handles data sync, and also some data processing. The data sync job is fairly obvious. PouchDB is a document database that runs in the browswer, and is designed for two-way sync with CouchDB. It's essentially a CouchDB implementation in the browser. One of the things both CouchDB and PouchDB do is build indexes of map-reduce queries over their data. LaminarNotes uses that feature to keep a cache of items sorted by their parent, which is quite handy for reconstructing and updating the item hierarchy.