Flux.ai is a complex, single-page web app that helps electronic engineers design printed circuit boards. As with any professional design tool, it needs to be fast, precise and predictable.
Early versions of Flux.ai were noticeably slow. We set a goal of making all our user interactions take less than 100ms, supported by science. We started a plethora of projects to make that happen, one of which I wrote about in another blog post. To make sure these efforts paid off, we created a measurement tool, log-time-to-next-idle, that is the subject of this blog post.
We've been using it to track the performance of around 50 key user interactions over 18 months, such as:
We're very happy with how it is working. And now we've shared it with the world as an open-source package.
A user interaction is defined here as any input the user provides—mouse click, key press, and so on—coupled with the intended effects of the input—menu opened, element added, and so on. The performance of a user interaction is simply the time between the start of the input to the end of the effects. For example, clicking on a select box will open a menu. The interaction is done when the menu has finished loading.
A subset of the interaction time is defined as “frozen time”. This is the interval following the user input when there are zero screen updates––no animation frames.
Although the concept of a user interaction is easy to define intuitively, the end state can be hard to define formally. In modern reactive UIs, any part of the UI can freely change in response to an update of a store of application state (Redux, Zustand, and so forth). The initial handler of some user input doesn't know all the downstream effects of its execution and so it can't mark the end of the interaction.

In the diagram above, it is hard to know which among the N components will determine the "end" of the interaction. You may not even know what are all the N components that react to some user inptu. To deal with this problem, we took a shortcut. Assuming that...
...we can leverage requestIdleCallback to mark when an interaction is done.
Similarly, we can leverage requestAnimationFrame to indicate when an interaction has yielded control back to the main thread, unfreezing the UI.
In short, log-time-to-next-idle measures user interactions by queuing a requestAnimationFrame and a requestIdleCallback at the start of an interaction, then recording the time when the callbacks fire.
Just put a call to logTimeToNextIdle at the start of any event handler. Here is an example of logging the time it takes to switch fictional tabs in a React app.
log-time-to-next-idle deals with overlapping interactions by cancelling earlier queued callbacks. In other words, the last interaction "wins" and any previous in-progress interaction is ignored. For ease of interpretation, you should try to measure debounced interactions that happen one at a time.
log-time-to-next-idle will store measured intervals in the browser using window.performance.measure (if available). The intervals will then show up in the profiler (if available).
Here is an example that logs to the console when in dev build mode, and logs to somewhere in the cloud when in prod build.
We hope this measurment function log-time-to-next-idle will be useful to you and your app, as well as the general approach of defining interaction end points in terms of CPU usage. Check out the open-source package and please post any feedback there.

A practical guide to Design for Manufacturing (DFM) that helps hardware teams transition from validated prototypes to scalable, production-ready products.

Practical PCB layout and design strategies to reduce EMI and improve the chances of passing FCC and CE compliance testing on the first attempt.

A guide to evaluating hardware feasibility through requirements definition, component selection, BOM cost estimation, power budgeting, and early manufacturing risk identification.

Learn how to choose the right hardware architecture by comparing the unique engineering priorities of robotics, wearables, and IoT products.

A practical guide to hardware prototyping—from breadboard to custom PCB, through structured testing, verification, validation, and iterative revision.

How electrical, mechanical, and firmware teams can build effective collaboration workflows through design reviews, revision control, and engineering change management.

Avoid costly errors in your PCB design with these expert tips! Discover the 5 most common mistakes in trace width, vias, power planes, and more. Learn how Flux’s AI Copilot helps you catch these issues early, ensuring your board is ready for manufacturing.

Explore the key aspects of PCB thermal analysis and discover best practices for enhancing your PCB design. Understand how thermal conductivity impacts heat management and overall PCB functionality, leading to more reliable and efficient circuits.