Move with arrows. Smoother remake of my 2013 entry, but the weather is not as nice this year.
for(_='){Z-1Y20XMath.WWcos(V*VUataTv[S++R256Q-X0*s+q*30*d-PQP384Ox=NNb/XLonkeyK(d-k)J))H);G)GF2*E+=%t=$0,#;b="/80 Wsqrt(=-4;Rt&3]55D[aR]==0;&511)for(Rf;--f&2;rgb2;;;}}512;a-=X64ZWmin(1,Wmax(#$(e-35)/tImageDT(Wsin(*eUC)+e*C)*t+(1-t)* *=y x*y;=2*%[#1,#Y][Vh)+X0*=$>St.keyCode&3]=.5*d 0;y=-d 0/2;p[*(y+m+(x+l]I=c.ge##i=,GD=I.dT;v=p=[];s=q=$Ny>y;y%!(Nx+1)p.push(52-Ux -y H)YGbRbYe6;$9*t+2+9Ut)&YZx;y3-;Sll-5;C=h=11)mm-5;)%.01}m=72;setInterval($>{s=s*.97+ES2]-ES0];Nyl%sUC=WTn2(C),VCH+qGm%s*CGq=q/2+S1]-S3];i=.9*i+5+5*Gd=k=43EC-67Eh%1/QGu=O*;d=-Q;Q>d;d%4Zf=,a=4*(*f-Q+d),eRe-300;ZNb=Gw=O*Eb/e+15*i/eGif(f>wZRy;y=.4+(b-H*h)Fg=rG$e/X#L;rNx/2+.75;gL||1"Gb>w}r=;g=118+11E"4*Fe=J*J+(f-u)*(f-uFY0FxGy=x (FN(99+1*H) x;QFr=r 2;g=g x"b y;e=40*/(QPfGN9*h+$-2-,-t*(Pf)/QFr.5+EH r;gVh-.2H g"(3Uh+.5HH b;c.puI,#0)},40GKdown.01;Kup0';G=/[^!&-DIM[-}]/.exec(_);)with(_.split(G))_=join(shift());eval(_)
Zm9yKF89Jyl7Wi0xWTIwWE1hdGguV1djb3MoVipWVWF0YVR2W1MrK1IyNTZRLVgwKnMrcSozMCpkLVBRUDM4NE94PU5OYi9YTG9ua2V5SyhkLWspSikpSCk7RylHRjIqRSs9JXQ9JDAsIztiPSIvODAgV3NxcnQoHz0tNDtSHnQmM10dNTUcRFthUl09Gz0wOxomNTExKRlmb3IoGBhSZjstLWYXJjIcOxsWG3IWZxZiFjIcFRU7FTsVOxV9fRQ1MTITO2EtPVg2NFoSV21pbigxLBFXbWF4KCMQJBARKGUtMzUpLw90SW1hZ2VEVCgOV3NpbigMKmVVQykrZSoMQykLKnQrKDEtdCkqCSo9eQl4Knk7CD0yHCoQByVbIzEsI1ldWwZWaCkFHCtYMCoQBD0kPlN0LmtleUNvZGUmM109Ay41CypkIDA7eT0tZCAwCy8yOwJwWxMqKHkrbRkrKHgrbBldAUk9Yy5nZQ4jI2k9EywTR0Q9SS5kVDt2PXA9W107GHM9cT0kTnkaEz55O3klIShOeCsxGSlwLnB1c2goETUyLRxVeCAtDHkgSClZRxhiGlJiWWU2OyQ5KnQrMis5VXQpJllaeAYdO3kGMy0dO1MdGhhsHmwtNTtDPWg9MTEpGG0ebS01OykBJS4wMX1tPTcyO3NldEludGVydmFsKCQ+e3M9cyouOTcrRVMyXS1FUzBdO055Gmwlc1VDPVdUbjIoDEMpLFZDSCtxR20lcyoMQ0dxPXEvMitTMV0tUzNdO2k9LjkqaSs1KzUqEAFHZD1rPTQzRUMtNjdFDGglMS9RR3U9TyoFOxhkPS1RO1E+ZDtkJTRaGGY9EyxhPTQqKBMqZi1RK2QpLGUaUmUtMzAwO1pOAmI9EAFHdz0QTypFYi9lKzE1KmkvZUdpZihmPndaUnk7eT0QES40KyhiLRABSCoMaClGZz1yBwVHJGUvWCNMO3IITngvMisuNzU7ZwhMfHwxIgQFR2IIFz53EhR9FxJyPRw7Zz0xMTgrMTFFBSIEETQqBUZlPR9KKkorKGYtdSkqKGYtdUYPWTBGeAcFR3k9eAkoBAVGTig5OSsxHCofEAVIKQl4Ow9RRnI9cgkyHDtnPWcJeCJiCXk7ZT00MCoTLyhRUGZHTjkqaCsCJBEQAS0yLQUsLXQqKFBmKS9RRnIHES41K0UFSAlyO2cHVmgtLjJICWciKAQRM1VoKy41SEgJYjsUYy5wdQ5JLCMwKX0sNDBHS2Rvd24DLjAxO0t1cAMwJztHPS9bXiEmLURJTVstfV0vLmV4ZWMoXyk7KXdpdGgoXy5zcGxpdChHKSlfPWpvaW4oc2hpZnQoKSk7ZXZhbChfKQ==
I=c.getImageData(0,0,i=512,512); D=I.data;
/* landscape generation */
v=p=[];
for (s=q=t=x=y=0;512>y;y+=!(x=x+1&511)) // 2-in-1 loop on x and y
p.push(Math.min(1,52-55*Math.cos(x/80-Math.sin(y/80)))-1); // initialize the heightmap with a sine-shaped river over a flat land
for (b=0;++b-1e6;t=9*t+2+9*Math.cos(t)&-1) { // 2.000.000 steps of pseudo-random walk
x+=[0,1,0,-1][t&3]; // not using actual random() to always generate the same heightmap
y+=[0,1,0,-1][3-t&3];
v[t&3]=0; // use the loop to initialize the controls as well
for (l=-4;++l-5;C=h=11) for(m=-4;++m-5;) // 11 ~ -1.57 radian : start at dawn, facing the sunrise
p[512*(y+m&511)+(x+l&511)]+=.01; // raise the land around : flat convolution filter
}
m=72; // start at (5, 72) with a nice view
setInterval( t=> {
s=s*.97+2*v[2]-2*v[0]; // alter speed when tilted forward or backward
x=y=0;
l+=s*Math.cos(C=Math.atan2(Math.sin(C),Math.cos(C))+q); // restrict yaw in [-pi, pi] as its raw value is used to position the sun
m+=s*Math.sin(C);
q=q/2+v[1]-v[3];
i=.9*i+5+5*Math.max(0,p[512*(y+m&511)+(x+l&511)]); // altitude autopilot, always fly above the ground
d=k = 432*C-672*Math.sin(h+=1/256); // sun X screen coordinate, needs yaw (C) in [-pi, pi]
u = 256-200*s+q*30*d-384*Math.cos(h); // sun Y screen coordinate, even below the horizon
/* draw the landscape */
for (d=-256; 256>d; d+=4) { // step size adjusted to get a reasonable framerate
for (f=512, a=4*(512*f-256+d), e=0; ++e-300; ) { // initialize y-buffer, drawing front to back
x=.5*e*Math.cos(C)+e*Math.sin(C)*d/800; // (x,y) matching world coordinate
y=-d/800*e*Math.cos(C)+e*Math.sin(C)/2;
b=Math.max(0,p[512*(y+m&511)+(x+l&511)]); // altitude at (x,y)
w=Math.max(0,256-200*s+q*30*d-384*2*b/e+15*i/e); // pixel height of the hill
if(f>w) { // y-buffer : only plot landscape visible behind the pixels already drawn
++y; // shadow computed from altitude difference along Y and sun direction
y=Math.max(0,Math.min(1,.4+(b-Math.max(0,p[512*(y+m&511)+(x+l&511)]))*Math.sin(h)));
g=r=255*Math.max(0,Math.cos(h)); // land color at horizon, dark blue at night, white at noon
t=e/200,
x=b/20; // grass color (b/20, b/20+0.5, b/20) : green at water level, white at altitude
r *= y*t+(1-t)*x*y; // water color (0/20, 0/20+0.5, 1)
x=x/2+.75; g*=y*t+(1-t)*x*y;
x=b/20||1;
b=55+200*Math.max(0,Math.cos(h));
b *= y*t+(1-t)*x*y; // blend color depending on distance and shadow
for (++f;--f>w;a-=2064) {
D[a++]=r&255;D[a++]=g&255;D[a++]=b&255;D[a++]=255;
D[a++]=r&255;D[a++]=g&255;D[a++]=b&255;D[a++]=255;
D[a++]=r&255;D[a++]=g&255;D[a++]=b&255;D[a++]=255;
D[a++]=r&255;D[a++]=g&255;D[a++]=b&255;D[a++]=255;
}
}
}
for (++f;--f;a-=2064) {
r=55;
g=118+112*Math.cos(h);
b=55+200*Math.max(0,Math.min(1,4*Math.cos(h)));
e=Math.sqrt((d-k)*(d-k)+(f-u)*(f-u));
//if (256>e) {
t=Math.max(0,Math.min(1,(e-35)/-10));
x = 255*Math.max(0,Math.cos(h));
y = x*t+(1-t)*(55+200*Math.max(0,Math.cos(h)));
x = (99+155*Math.sqrt(Math.max(0,Math.cos(h))))*t+(1-t)*x;
t=Math.max(0,Math.min(1,(e-35)/256));
r=r*t+(1-t)*255;
g=g*t+(1-t)*x;
b=b*t+(1-t)*y;
//}
e=40*512/(256-200*s+q*30*d-f);
x=9*h+.5*e*Math.cos(C)+e*Math.sin(C)*d/800; // (x,y) matching world coordinate
y=-d/800*e*Math.cos(C)+e*Math.sin(C)/2;
// blend with horizon/clouds
t=Math.min(1,Math.max(0,p[512*(y+m&511)+(x+l&511)]-2-Math.cos(h), -t*(-200*s+q*30*d-f)/256));
r=255*Math.max(0,Math.min(1,.5+2*Math.cos(h)))*t+(1-t)*r;
g=255*Math.max(0,Math.cos(h-.2))*t+(1-t)*g;
b=(55+200*Math.max(0,Math.min(1,3*Math.cos(h+.5))))*t+(1-t)*b;
D[a++]=r&255;D[a++]=g&255;D[a++]=b&255;D[a++]=255;
D[a++]=r&255;D[a++]=g&255;D[a++]=b&255;D[a++]=255;
D[a++]=r&255;D[a++]=g&255;D[a++]=b&255;D[a++]=255;
D[a++]=r&255;D[a++]=g&255;D[a++]=b&255;D[a++]=255;
}
}
c.putImageData(I,0,0);
}, 40); // target 25 FPS
onkeydown = t=>v[t.keyCode&3]=.01;
onkeyup = t=>v[t.keyCode&3]=0