With the newer audio and timing paths settling into place, we have started looking more closely at the work still being driven by the gameplay frame loop.

Over the years, several responsibilities accumulated around the code that tracks notes crossing rows. That path now touches holds, checkpoints, assist sounds, misses, theme messages and cabinet lighting, even though those events do not all need to be checked or triggered every time a frame is drawn.

This can be difficult to spot during normal play. Each individual operation is small, and the engine still produces the expected result. The problem becomes clearer when the same work is repeated hundreds or thousands of times simply because the frame loop continues to run.

We have added StillRiver measurements around these row and gameplay-window paths so we can see what is happening before changing their behaviour.

The aim is not to pull the whole system apart at once. Some of this code controls gameplay behaviour that has existed for many years, across different modes and themes. Changing too much in one pass would make it harder to tell whether a fault came from the original behaviour or from the rewrite.

The first adjustment has been made to gameplay-side lighting updates.

Those updates are now limited to a steady 60 Hz instead of running at the full gameplay frame rate. The existing global lighting option is unchanged, and the lower-level lights manager has been left alone. This only prevents the gameplay path from asking for the same lighting work more often than it can usefully change.

It is a deliberately small change, but it gives us a clean result to measure before moving further into the row-processing code.

The longer-term work is to separate actions that currently happen together simply because they share an old update path. Row crossings should happen when the song reaches them. Input work should happen when an input arrives. Lighting should update when a lighting event is due. Presentation can continue to follow the frame loop.

StillRiver is helping us identify those boundaries without guessing or rewriting working behaviour for the sake of tidier code.

There is more to untangle here, but the first unnecessary work has now been removed without changing scoring, chart timing or input handling.