GLSL HARD Problem: Dynamically calculated normals in shader work on wrong axis

I’m trying to get this cool LOD terrain system to work but normals don’t want to behave correctly. I extracted this system from a browser game called Trigger Rally. It took me ages to get this to work. It was written in CoffeeScript and for a very old version of Three.js. Finally it works, the shadows work but the normals are a massive pain.

Light is circling over the terrain and a ball drops a shadow to help understand where the light is coming from.

Here’s a version with detailed normals, independent from vertex shader. They behave like if the light was travelling on another axis

Here’s the version with uncommented piece of code that makes the normals work but they only have vertex shader resolution. Very angular:

The relevant shader code in in renderTerrain.js line 530

It’s worth mentioning that the original game is working in Z up world and I managed to get this shader to work in Y up world. Except of the normals.