the single LED and row/col commands are bandwidth-optimized only if you’re doing very simple operations— and in the early days we had tons of patches that did simple stuff where this was enough.
i’ve long since abandoned this approach. on norns and the eurorack modules the only serial packets sent are full 8x8 “map” arrays, if the area is dirty. granted, there’s no OSC flying around.
my suggestion: for complex applications (even in max, use js instead) just redraw the entire 8x8 grid every refresh. you can get very fast refresh rates this way, and the CPU will hardly suffer.
you can have separate functions for drawing a nav bar, different views, etc, and they all can just get called by a central grid redraw. this redraw can even be on a timer so you don’t need to worry about dirty states (less efficient, but nothing will explode).
the nodejs grid study is the right track (and largely relevant to max/msp js): https://monome.org/docs/grid/studies/nodejs/
or, also check out my work-in-progress rewrite of mlr (the grid portion) which lays out “pages” with a “nav row” and nicely divides the code for readability: https://github.com/tehn/mlr/blob/dev/lib/grid.lua