|
I've published a guide to Ooloi's frontend architecture – long, precise, and detailed, written for architects and developers who want to understand the system from the inside.
It covers window lifecycle, event architecture, the rendering pipeline, fetch coordination, localisation, collaboration, and the testing model. Together with the Timewalking Guide and the Polymorphic API Guide, it forms the main conceptual gateway into Ooloi's internals. Worth flagging for experienced frontend developers: this architecture inverts several instincts. The frontend holds no semantic authority. It is computationally strong and structurally subordinate; that subordination is precisely what makes distributed collaboration, transport independence, and first-class plugin composition possible without architectural compromise. The guide explains why. I think the argument is sound, though I'm aware it might feel distinctly odd, or even regressive, to a developer whose instincts were formed in React or a similar ecosystem. If you work in notation – as a musician, engraver, or editor – and find this kind of writing opaque, current large language models are genuinely useful here. Feed the guide to one and ask what it means for your daily work. It's a reasonable use of the technology, and the answers tend to be surprisingly good – when they're not inventing things I'd never claim ;) Worth stating plainly: the subject here is art, and the technical rigour exists in service of that, not despite it. This blog documents the reasoning behind Ooloi as it develops – for future contributors, researchers, maintainers, and critics. Systems like this have a lineage and a psychological architecture as much as a technical one. I want that visible. This blog has a voice because it was written by someone who considers authorial invisibility a failure mode rather than a virtue.
0 Comments
Ooloi is now a running desktop application on macOS, Windows, and Linux. It opens, it responds, it remembers where you left it. A concrete thing, like any other program.
But that's not enough. The next step is teaching it to talk. Ooloi's frontend and backend have always been separate components communicating through a defined protocol; in standalone mode, they simply appear as one and the user needn't think about it. But this disciplined split personality was designed that way for a reason, and it's now time to act on it. ADR-0036 lets the two halves run apart — so one Ooloi can connect to another, or to a centralised server. You invite a collaborator; a secure connection opens. They disconnect; the application returns to working alone. No restart, no mode switching. The separation was always there. Now it becomes visible. After nineteen months of building systems that nobody can see – temporal traversal, accidental algorithms, transducer pipelines, STM coordination – I have spent the past fortnight making menus behave. Menus. On three operating systems. macOS wants an application menu in the system bar. Windows wants Exit in the File menu and About in the Help menu. Linux wants Quit in the File menu and Settings in the Edit menu. None of them is wrong, exactly, but none of them agrees with the others, and they all have opinions. This is normal engineering. It is, after the intensity of the semantic work, refreshingly boring. Dark mode and light mode. A splash screen that shows each component as it initialises. Window state persistence so the application remembers where you left it. An About dialog with a background of engraved music, rendered through the same windowing path as everything else. Translation keys for every user-visible string, verified at build time against PO files. Fixing the JVM's 64KB static initialiser limit because 185 multimethod symbols turned out to be too many for a single class. Stripping debug symbols from the jlink runtime to bring the application bundle down from 213 MB to 173 MB. None of this is interesting in the way that a deterministic accidental rendering algorithm is interesting. And that's the point. Ooloi now has a face and a body. It boots, shows what it's doing, presents platform-appropriate chrome, responds to commands, and shuts down cleanly. The experience of seeing it is strange – like hearing a recording of a piece you've been composing in silence. You know every voice, every structural decision, but the thing sitting there on the screen, with its dark window and its OK button, is suddenly external. It exists in the world rather than in your head. The project board tells the story plainly enough: 61 tickets closed, the combined application framework just completed, and one ticket in progress. That ticket is multi-mode clients – the work that will let an Ooloi talk to other Oolois and to dedicated servers. A student working alone invites a teacher; the teacher connects, helps, disconnects, resumes their own work. An institution runs a 24/7 server. A string quartet in four cities annotates bowings in the same score.
This is why I'm doing it now, before rendering, before input, before any of the visible musical functionality. Collaboration in Ooloi isn't a feature bolted on at the end; it's a consequence of the architecture. Immutable data, STM transactions, gRPC transport, VPD-based addressing – these were built for correctness, not for collaboration, but they make collaboration nearly trivial. The hybrid transport architecture lets the application start standalone and accept collaborators dynamically, without restart, without mode switching. Once this works – and it will work, because the foundations were built for it whether I knew it at the time or not – I need not spend any more time on it for the foreseeable future. Then the real work begins: making Ooloi do what it was built to do. Drawing music. But for now, I'm fixing a macOS bug where "Show All" doesn't unhide windows, and adding a theme toggle. Ordinary work. I find I don't mind it. We have a new year, and it's time to make plans. Ooloi's architecture is now closed, and the work enters a new phase. What follows is a road map, not a schedule – no dates, no promises – but a logical progression. These stages are different in nature from what has gone before. Conceptually simpler than the deep semantic work (what the music is, how it's represented and manipulated) or the infrastructure (server/client transports and roundtrips, monitoring, certificates). Everything below is comprehensively architectured and implementation-ready. The thinking is done; what remains is execution. The PreparationsEvent-Driven Client Architecture: The nervous system that lets the interface respond without freezing. (ADR-0022, ADR-0031)
Windowing System: Windows, menus, palettes, dialogs, notifications, connection status. The application becomes something you can see and touch. (ADR-0005, ADR-0038) Multi-Mode Clients: Standalone operation, peer-to-peer connection, shared server connections. (ADR-0036) Skija / GPU Rendering: The drawing substrate. GPU-accelerated graphics, paintlist caching, lazy fetching. The machinery for putting marks on screen. (ADR-0005, ADR-0038) Hierarchical Rendering Pipeline: The transformation from musical structure to visual layout. (ADR-0028, ADR-0037) Plugin System: First-class access from any JVM language. (ADR-0003, ADR-0028) MusicXML: The first, limited version, implemented as a canonical plugin. Real scores entering the system. (ADR-0030) And then – and only then – will the first staff line appear. After a year of building infrastructure, it seemed worth finding out whether it actually worked. The test was simple: create a million rests and see what happened. One operation – – repeated until either something broke or the numbers settled. Single Thread, Single ClientFirst experiment: one client, one thread, a million sequential calls. This was on a 2017 MacBook Pro, so not exactly cutting-edge hardware. Every call succeeded. Average execution time was 35 microseconds. Memory stayed at 112 MB without drifting upwards. Garbage collection remained in the young generation. Thread count didn't move. Zero errors. Nothing dramatic, which was the point. Adding ConcurrencySecond test: four threads on one client, 250,000 calls each. Another million operations, but with some concurrency this time. Same result. All calls succeeded, memory stayed flat, garbage collection behaved, threads were stable. Still zero errors. This level of concurrency should be unremarkable for any serious system. It was. Multiple ClientsThird experiment: ten clients, four threads each. Forty threads total – enough to make the laptop work. Average call times went up to 246 microseconds, but everything else held steady. Memory stable, garbage collection well-behaved, threads disciplined. Error count still zero. Same 2017 laptop that started the tests. What This MeansFrom one thread to forty, from 35 microseconds to 246, the pattern was consistent. The system handled load without breaking.
These were only raw API calls, not STM transactions with musical logic and collaboration on top. Those will be next. For now, the figures suggest the foundations are fast, steady, and ready to carry more. Three tests left on the visibility work. After that, this part of the system is done. It’s taken a few weeks to get the final bits of the gRPC server/client interaction implemented, but it now feels solid. The server reliably and efficiently handles all the complex aspects of live clients connecting, disconnecting, and communicating locally or over the inherently chaotic internet. With that done, the focus is now on what is called observability: being able to see what's going on inside. In other words, server statistics. We’re now tracking server-wide and per-client metrics: connections, API call rates, message sizes, event streaming, queue overflows. Endpoints can return JSON during development or Prometheus format in production. Content negotiation is automatic, or you can force a format with a query parameter. No new tools to learn. Grafana dashboards work straight away. Why this matters for musicians: research has shown that in collaborative settings, users prefer a notation program that lets them work together over one with the most features. That says everything about how poorly existing software supports collaboration. It’s treated as an optional extra, if it exists at all. Ooloi is built differently. Collaboration is not bolted on afterwards but designed into the system from the start. If event queues slow or connections drop, collaboration breaks down. A slur added on one screen never appears on another, or two edits collide and the score diverges. The statistics make these problems visible. They show when the system is stressed, when clients are falling behind, when the score risks drifting out of alignment. In short, they make collaboration trustworthy. And unlike the current trade-offs, Ooloi isn’t choosing collaboration instead of notational depth. It is designed to be both: a serious, advanced notation platform that also makes shared editing reliable. The same architecture also opens up another possibility. Because Ooloi is client/server, it can stream smoothly scrolling scores in real time. That makes digital music stands for ensembles or orchestras feasible. It’s not the main focus, but it’s there: the professional counterpart to the school-level collaboration studies. Three tests left. Once they pass, the intricate server machinery will be visible. And visibility is the first condition for trust. Deep in the implementation of the gRPC layer I fell into the same foxhole as so many gRPC developers seem to do: implementing streaming between gRPC server and client using in-process communication. Everything works swimmingly: high speed, nothing gets lost, advanced async patterns just work.
And then they try doing this using network transport. Suddenly HTTP/2 changes everything, and that equivalence between simple request-response and asynchronous streaming just explodes. I spent a couple of days cursing the universe, but in the end I managed to crawl up into the daylight again with a solid solution. Since this seems to be a common snag, I decided to publish a little guide on the considerations involved, so others may have to do less cursing. Here it is: GRPC_STREAMING_THREADING_GUIDE.md Nearing the end of the gRPC implementation phase now: coming blog posts should soon become more musical again. The Ooloi server must of course also have comprehensive introspective statistics, as it can be deployed in several ways and has a structure which is perhaps a bit unusual. The combination of STM-wrapped gRPC API calls with server-to-client event streaming creates some operational challenges: things like per-client queue overflow behaviour and collaborative editing session patterns.
Hence this new ADR on server statistics, which takes a two-level approach: server-wide aggregates that survive client churn, plus detailed per-client metrics for operational visibility. Oh, and it interfaces with Grafana, Prometheus, and friends straight out of the box via simple HTTP endpoints. Halfway through the stats implementation now. It's been a productive weekend.
I've just published ADR-0024 and, based on it, a new gRPC Communication Guide documenting when flow control helps and when it interferes. The decision was straightforward once the analysis was done: implement flow control for event streaming (where slow clients can block fast ones) but avoid it entirely for API requests (where gRPC's threading model and STM transactions already coordinate beautifully). Sometimes the most sophisticated solution is knowing where not to add sophistication. The guide covers the technical reasoning and includes practical examples for anyone implementing gRPC clients, regardless of language choice. |
AuthorPeter Bengtson – SearchArchives
April 2026
Categories
All
|
|
|
Ooloi is an open-source desktop music notation system for musicians who need stable, precise engraving and the freedom to notate complex music without workarounds. Scores and parts are handled consistently, remain responsive at scale, and support collaborative work without semantic compromise. They are not tied to proprietary formats or licensing.
Ooloi is currently under development. No release date has been announced.
|


RSS Feed