Ugh, it's been in front of my eyes all along. The logs have been
repeatedly showing a recurrence within a single frame:
key press -> update Viewport.y from screen_top -> A -> B -> update_editor_box -> update screen_top from Viewport.y
We need both those updates, but both should never occur at the same
time to the same node.
I think this is why screen panning works if I take out the scale inside
update_editor_box: the scale has already happened "once" in
updating Viewport.y, and it doesn't converge if we perform it a second
time in a frame. But the solution is just to do one or the other to a
node, never both.
I knew this (learned it the hard way) when I first built pensieve.love,
and I had an assertion to avoid it. But my assertion was brittle, and it
kept failing, and I took it out, and then I slowly took out all the code
that prevented this recurrence.
Panning with a cursor inside a node is working fine.
The relationship between y_of_schema1 and schema1_of_y is preserved.
I understand why I shouldn't scale the y in the call to schema1_of_y.
I'm also feeling a little more confident about why lines.love shouldn't
use coordinate transforms. The problem is that text gets blurry if it
starts at non-integer coordinates. We're forced to get into special
cases.
There's still the outstanding issue that the surface y coordinate of
each screen line is not consistent as you pan around (and the editor
starts off-screen above the viewport).
If you have just text boxes it's only noticeable when one box's top
margin is visible and another is not. Then the text in the two moves
relative to each other.
This is a big change, and I'd have to first modify lines.love to use the
coordinate transforms. And that fork doesn't really need a principled
coordinate system.
Unscaled y makes cursor scrolling more stable, but it seems to be
compensating for an error elsewhere. The location of the top margin of
text is not stable, and I only notice when I can see the bottom margin
of the bounding box. (When the top margin is visible we never enter that
branch in update_editor_box.)
I should just use LÖVE's standard translation and scaling transforms for
the surface! Don't know why I didn't think of that.