### Stars and text intro

The opening scene of **Enigma** by **Phenomena** starts out looking like an average side-scrolling star parallax, which was very normal in 1991. Nice way to lower people’s expectations. ðŸ™‚ But after just a couple of seconds, the stars begin twisting and turning in space around all three axes.

Back in 1991 I knew how to rotate a plane around the origo, by simply applying the angle sum identities of Sine and Cosine. I also realized that rotating any 3D coordinate in space could by done by simply the case of rotating around more than one axis, one axis a time.

In the **Phenomenal & Enigmatic** demo, I only rotate the stars around two axes. First I rotate the `(x,z)`

components around the Y axis to get `(x',z')`

, and then the `(y,z')`

components around the X axis to get `(y',z'')`

. I also translate each star along the X axis before the rotation takes place. To finally get the 2D screen coordinates of the 3D space coordinate, I take the `(x',y')`

coordinate and multiply by `(2/(2+z''))`

for a pseudo-distance feel. The `z'`

‘ value controls both the color alpha component, and the size of the rectangle being drawn.

The even better way of doing this is through vector addition and multiplication, but I’m sticking to the math that I know. ðŸ™‚ After all this math is in place, the trick is to change the offset and rotation variables in a nice way.

Rendering text is just a couple of calls to the `context.fillText`

method and animating the value of `context.globalAlpha`

.

### Pseudo code

```
// Prefetch sin and cosine of angles
var cosY = Math.cos(yAngle);
var sinY = Math.sin(yAngle);
var cosX = Math.cos(xAngle);
var sinX = Math.sin(xAngle);
for (var star, i = 0; star = stars[i++]; ) {
// Fetch x, y, z and translate x
var x = star.x + xOffset;
var y = star.y;
var z = star.z;
// Limit x to [-1 .. 1]
while (x > 1) x -= 2;
while (x < -1) x += 2;
// Rotate (x, z) around Y axis
var x2 = x * cosY + z * sinY; // x'
var z2 = z * cosY - x * sinY; // z'
// Rotate (y, z') around X axis
var y2 = y * cosX + z2 * sinX; // y'
var z3 = z2 * cosX - y * sinX; // z''
// Transform to screen coordinates
var screenX = x2 * 2 / (2 + z3) * halfScreenWidth + halfScreenWidth;
var screenY = y2 * 2 / (2 + z3) * halfScreenWidth + halfScreenHeight;
// Draw the star
context.fillRect(screenX, screenY, 2 - z3, 2 - z3);
}
```

- Phenomenal & Enigmatic, part 1
**Phenomenal & Enigmatic, part 2***(this part)*- Phenomenal & Enigmatic, part 3
- Phenomenal & Enigmatic, part 4

The entire demo, including non-minified JavaScript, is available on GitHub: /lbrtw/enigmatic