Nothing too hard to begin with;
At first I thought that I must be scaling my normals, and forgetting to re-normalise them. Then nope - still dark colours and grey-ish looking where it should be black. I used the dot product result and also its negative as colours - seemed fine. Then it occured to me that my usual lighting equation from OpenGL was doing something unexpected:
It works like this mathematically (component-wise multiplication):
Now, the alpha channel is also multiplied by the factor. Normally, this doesn't do anything in OpenGL unless you explicitly enable a blend mode first. Then you can use it to make your fragments transparent. I suspected something so I set Id.a = 1.0 after the lighting equation. And it fixed the problem! It turns out that in WebGL, there is a default blend mode enabled somewhere that was showing the background of the HTML page through the fragment - making it look grey (my webpage was grey).
I first went for the basics and wrote a Camera object where pressing W,A,S,D keys would move the camera along -Z,-X,+Z, and +X axes, respectively. No sweat but the camera was always facing forward. I used the mouse cursor to rotate a vector that I was using in the lookAt function. I ran into a very strange problem then. Moving forwards and backwards in the direction of the camera was fine, but left and right was not. I used the cross() function from gl-matrix.js to define a sideways-pointing vector, but the function was not returning the correct result when I laid it out like this: var sideVec = vec3.cross (forwardVec, [0 1 0]);. I changed the parameters around and set it up like: vec3.cross (forwardVec, [0, 1, 0], sideVec); and it was fine.
I dread implementing texture shadows in normal OpenGL. Do I dare? Probably not. I could move onto building a more generic engine type of thing but I don't have any real project specs yet. I guess I'm up to fluffing around with the experimental parts. I will need to do some animation software eventually, so perhaps I should have a look at building a hardware skinning demo using some sort of JSON script for animation.