Procedural animated texture generation/Nether portals

Due to the large number of Atan2 and Sine operations, all of the animation frames for the portal block are generated once at-startup, with each frame's data being stored in an array of all the frames.

To generate a frame of the Nether portal animation: Assume width = 16, height = 16, and frame_count = 32. Additionally, assume {hw, hh} = {width / 2, height / 2}, rounding down.

for every frame, with frame_index being the iterator: for every pixel, with {x, y} being the iterators: let float n = 0 // we repeat this twice to create two spirals. one rotating clockwise and another offset // to the top right of our position that rotates anti-clockwise. This is so the texture can // tile reasonably well (at this low resolution). repeat twice, with i being the iteration: let floats {spiral_x, spiral_y} = ({x, y} - (i * {hw, hh})) / {w, h} * 2. if {spiral_x, spiral_y} is less than -1, add 2. If greater or equal to 1, subtract 2 let float mag = power(spiral_x, 2) + power(spiral_y, 2) let float out_spiral = atan2(spiral_y, spiral_x) // Normalize the frame's index into a 0-1 range, and then into an angle from 0-360 (as radians) // Mag is subtracted from this equation to cause the spiral arms to constrict with distance from the centre // (i * 2 - 1) will multiply out_spiral by -1 if i is 1. out_spiral += ((frame_index / frame_count * PI * 2) - (mag * 10) + (i * 2)) * (i * 2 - 1) // this will bring the results of the sine operation into the range of 0 to 1 rather than -1 to 1 out_spiral = sin(out_spiral) * 0.5 + 0.5 // make the intensity of the spiral's arms diminish with distance from the centre. out_spiral /= mag + 1 // since we're generating two spirals, we divide by 2 so that the final range is 0 to 1 instead of 0 to 2. n += spiral / 2 // make the spirals shimmer slightly at random n += random(0.0, 1.0) * 0.1 let byte r = floor(n * n * 200 + 55) let byte g = floor(power(n, 4) * 255) let byte b = floor(n * 100 + 155) let byte a = b           frames[frame_index].frame_data.rgba at {x, y} = {r, g, b, a}

Note that Minecraft performs almost all of its color calculations in linear space, and only applies gamma correction near the end of rendering. If your Nether portal's colors appear to be off, apply a gamma correction of 2.2.