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.
TZNPEHB3BRUHATVYAODURZUR45TYV62HYWQK5SUXHAOLVGYJVP7AC
F5BF4M6KKVFYOO65BMF3TNRTYIOHNVVMPLEQSSX6UCNOOEQMKIIAC
QJAYOFWY7V4BWVLJMEDCCBC2HX4BDAZI6PQVLWCLYRHWGMOBFTVAC
SY5SNGKD3JUF3S6Q3RVOWEXMKOEQUXFKFRLMSLBPE6RN4YU7DAZQC
P36KIMZCWGBG6CZQE3W5SVTCJMYZOVEZ3U3FAF46SO5ZMMM42PHQC
WKMW7PCE75A5CFXF5GPL5HQ4ZNASFOFQFHASOQ7LABSQKWU3KEGAC
PPVABNGQTQMPYILHDNSNXBI5IOCBSIYO45NIHUR4LYPABQZE6PAQC
TK73HJVXQCBEEN4ATMLSSG4DI2XZJAQEJICJ472E3YAW55EFAT5AC
KAGTD334AIWFI34VE34OARC44BZDUJRP5R3ZTT6JCQGSYYC3GTVQC
JIBCE66ZTWM5WEHEHNKKTRWBJQSQWBDDWPMOJIJR5Q676OSHYCNAC
6KFND4SU2O7UDJVSS74YI3PI453ZFCBM72P6TWLI7DSKFEVUQVFQC
AYUZF67YZY2GQBYJJLHU6LI7KJUTBRPYY46WOD4MBVE3DIGSLM2QC
TTMMK6S6ILBQ6YN6H2DR5I5PH4ZUITWAGG72AJWLKLKGO5AATT2AC
print('viewport', Viewport.y)
print('node', Page.data[1].y)
print('node renders from', Page.data[1].editor.top)
print('screen top', Page.data[1].editor.screen_top1.line)
print('viewport', Viewport.y, 'spx')
local node = Page.data[1]
print('node', node.y, 'spx')
print('line height', node.editor.line_height, 'vpx')
print('node renders from', node.editor.top, 'vpx')
print('screen top', node.editor.screen_top1.line)
print('invariant', Viewport.y-node.y+node.editor.top - y_of_schema1(node.editor, node.editor.screen_top1))
-- translate Page to Surface
while #Surface > 3 do table.remove(Surface) end -- HACK
local red = false
for x=-1000,2000,300 do
for y=-10000,10000,200 do
add_thick_line({type='line', data={x,y, x+200,y+200, x,y+400}, r=red and 1 or 0,g=red and 0 or 0.5,b=0}, 10)
red = not red
end
end
Surface = {}