Skip to content

Instantly share code, notes, and snippets.

@FransBouma
Last active June 24, 2019 10:50
Show Gist options
  • Save FransBouma/6959f3b75ebccb9078d716e72b0cb053 to your computer and use it in GitHub Desktop.
Save FransBouma/6959f3b75ebccb9078d716e72b0cb053 to your computer and use it in GitHub Desktop.
Starfield JS
<!DOCTYPE HTML>
<html>
<head>
<title>Simple full-browser star field effect in JS. By Otis / Infuse Project.</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
</style>
<script lang="javascript">
// VBL
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (/* function */ callback, /* DOMElement */ element) {
window.setTimeout(callback, 1000 / 60);
};
})();
window.onresize = function () {
fb.resize();
}
// constants
var MAXZ = 4096;
var SCREENZ = 32;
var NUMBEROFSTARS = 16384;
// globals
var fb, counter, stars;
function init() {
fb = new frameBuffer('fbDiv');
counter = Math.floor(fb.width / 2);
stars = new Array(NUMBEROFSTARS);
for (i = 0; i < NUMBEROFSTARS; i++) {
stars[i] = new star(fb.width*64, fb.height*64);
}
renderLoop();
}
function renderLoop() {
requestAnimFrame(renderLoop);
renderFrame();
}
function renderFrame() {
fb.clear();
for (i = 0; i < NUMBEROFSTARS; i++) {
stars[i].move();
stars[i].project(fb.width, fb.height);
}
fb.drawStars(stars);
}
function frameBuffer(id) {
this.canvas = document.createElement('canvas');
this.canvas.style.position = 'absolute';
this.canvas.style.left = this.canvas.style.top = '0px';
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
//var parentDiv = document.getElementById(id);
document.body.appendChild(this.canvas);
this.width = this.canvas.width;
this.height = this.canvas.height;
this.ctxt = this.canvas.getContext('2d');
this.clear = function () {
//this.ctxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.fill(0, 0.1);
}
this.fill = function (color, alpha) {
this.ctxt.save();
this.ctxt.globalAlpha = alpha;
this.ctxt.fillStyle = color;
this.ctxt.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctxt.restore();
}
this.resize = function () {
if (this.canvas) {
this.canvas.setAttribute('width', window.innerWidth);
this.canvas.setAttribute('height', window.innerHeight);
this.width = this.canvas.width;
this.height = this.canvas.height;
this.ctxt = this.canvas.getContext('2d');
}
}
this.drawStars = function(stars) {
var byteBuffer = this.ctxt.getImageData(0, 0, this.canvas.width, this.canvas.height);
for (i = 0; i < NUMBEROFSTARS; i++) {
var star = stars[i];
if (star.renderStar) {
// calculate color alpha from z. the farther away, the less bright (so alpha nears to 0 with MAXZ
var color = Math.floor(255 * (1.0 - ((star.z - SCREENZ) / (MAXZ - SCREENZ))));
this.putPixel(byteBuffer, star.projectedX, star.projectedY, color, color, color, 255);
}
}
this.ctxt.putImageData(byteBuffer, 0, 0);
}
this.putPixel = function(buffer, x, y, r, g, b, a) {
var index = (y * this.canvas.width * 4) + (x * 4);
buffer.data[index] = r;
buffer.data[index + 1] = g;
buffer.data[index + 2] = b;
buffer.data[index + 3] = a;
}
}
function star(maxWidth, maxHeight) {
this.projectedX = 0;
this.projectedY = 0;
this.renderStar = false;
// move origin to center of canvas, so pre-calc x/y according to this.
this.x = (Math.random() * maxWidth) - (maxWidth/2);
this.y = (Math.random() * maxHeight) - (maxHeight/2);
this.z = Math.random() * MAXZ;
this.precalcX = Math.floor(this.x * SCREENZ);
this.precalcY = Math.floor(this.y * SCREENZ);
this.speed = Math.random() * 10;
if (this.speed < 1) {
this.speed = 1;
}
this.move = function() {
this.z = this.z - this.speed;
if (this.z <= 1) {
this.z = MAXZ;
}
}
this.project = function(maxWidth, maxHeight) {
this.projectedX = Math.floor(( this.precalcX / this.z) + (maxWidth/2));
this.projectedY = Math.floor(( this.precalcY / this.z) + (maxHeight / 2));
this.renderStar = ((this.projectedX >= 0) && (this.projectedX <= maxWidth) && (this.projectedY >= 0) && (this.projectedY <= maxHeight));
}
}
</script>
</head>
<body style="background-color:#000;">
<div id="fbDiv">
</div>
<script>
init();
</script>
</body>
</html>
<!DOCTYPE HTML>
<html>
<head>
<title>Simple full-browser star field effect in JS. By Otis / Infuse Project.</title>
<style type="text/css">
body {
margin: 0;
padding: 0;
}
</style>
<script lang="javascript">
// VBL
window.requestAnimFrame = (function () {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function (/* function */ callback, /* DOMElement */ element) {
window.setTimeout(callback, 1000 / 60);
};
})();
window.onresize = function () {
fb.resize();
}
// constants. X and Y follow normal canvas coordinate system. Z is positive into the screen.
var MAXZ = 4096;
var SCREENZ = 32;
var NUMBEROFSTARS = 16384;
// globals
var fb, stars, moveDirection, worldMaxX, worldMaxY;
function init() {
fb = new frameBuffer('fbDiv');
stars = new Array(NUMBEROFSTARS);
worldMaxX = fb.width * 64;
worldMaxY = fb.height * 64;
for (i = 0; i < NUMBEROFSTARS; i++) {
stars[i] = new star();
}
moveDirection = new moveVector();
renderLoop();
}
function renderLoop() {
requestAnimFrame(renderLoop);
renderFrame();
}
function renderFrame() {
//fb.fill(0, 0.5);
fb.clear();
moveDirection.tick();
for (i = 0; i < NUMBEROFSTARS; i++) {
stars[i].move(moveDirection);
stars[i].project(fb.width, fb.height);
}
fb.drawStars(stars);
}
////////////
// moveVector
////////////
function moveVector() {
// angles in degrees.
this.alpha = 0;
this.beta = 90;
this.gamma = 275;
this.dx = 0;
this.dy = 0;
this.dz = 0;
this.r = 10;
this.tick = function () {
this.alpha += 0.1;
this.beta -= 0.05;
this.gamma += 0.1;
if(this.alpha > 360) {
this.azimuth = 0;
}
if (this.beta <0) {
this.beta = 360;
}
if (this.gamma > 360) {
this.gamma = 0;
}
this.convert();
}
this.convert = function () {
// convert angles to radians, then calculate sin/cos for deltas.
this.dx = Math.sin(2 * Math.PI * (this.alpha / 360)) * this.r;
this.dy = -Math.cos(2 * Math.PI * (this.beta / 360)) * this.r;
this.dz = (Math.sin(2 * Math.PI * (this.gamma / 360)) * this.r)/8;
}
}
////////////
// frameBuffer
////////////
function frameBuffer(id) {
this.canvas = document.createElement('canvas');
this.canvas.style.position = 'absolute';
this.canvas.style.left = this.canvas.style.top = '0px';
this.canvas.width = window.innerWidth;
this.canvas.height = window.innerHeight;
var parentDiv = document.getElementById(id);
parentDiv.appendChild(this.canvas);
this.width = this.canvas.width;
this.height = this.canvas.height;
this.ctxt = this.canvas.getContext('2d');
this.clear = function () {
this.ctxt.clearRect(0, 0, this.canvas.width, this.canvas.height);
}
this.fill = function (color, alpha) {
this.ctxt.save();
this.ctxt.globalAlpha = alpha;
this.ctxt.fillStyle = color;
this.ctxt.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctxt.restore();
}
this.resize = function () {
if (this.canvas) {
this.canvas.setAttribute('width', window.innerWidth);
this.canvas.setAttribute('height', window.innerHeight);
this.width = this.canvas.width;
this.height = this.canvas.height;
this.ctxt = this.canvas.getContext('2d');
}
}
this.drawStars = function(stars) {
var byteBuffer = this.ctxt.getImageData(0, 0, this.canvas.width, this.canvas.height);
for (i = 0; i < NUMBEROFSTARS; i++) {
var star = stars[i];
if (star.renderStar) {
// calculate color alpha from z. the farther away, the less bright (so alpha nears to 0 with MAXZ
var color = Math.floor(255 * (1.0 - ((star.z - SCREENZ) / (MAXZ - SCREENZ))));
this.putPixel(byteBuffer, star.projectedX, star.projectedY, color, color, color, 255);
}
}
this.ctxt.putImageData(byteBuffer, 0, 0);
}
this.putPixel = function(buffer, x, y, r, g, b, a) {
var index = (y * this.canvas.width * 4) + (x * 4);
buffer.data[index] = r;
buffer.data[index + 1] = g;
buffer.data[index + 2] = b;
buffer.data[index + 3] = a;
}
}
////////////
// star
////////////
// World origin is 0,0 which is at top left. Z is positive inside the world.
function star() {
this.projectedX = 0;
this.projectedY = 0;
this.renderStar = false;
this.x = (Math.random() * worldMaxX);
this.y = (Math.random() * worldMaxY);
this.z = Math.random() * MAXZ;
this.speed = Math.random() * 10;
if (this.speed < 1) {
this.speed = 1;
}
this.move = function (v) {
this.x += Math.floor(v.dx * this.speed);
this.y += Math.floor(v.dy * this.speed);
this.z += Math.floor(v.dz * this.speed);
// clamp.
if(this.x < 0) {
this.x = worldMaxX - (0 - this.x);
}
else {
if (this.x > worldMaxX) {
this.x -= worldMaxX;
}
}
if (this.y < 0) {
this.y = worldMaxY - (0 - this.y);
}
else {
if (this.y > worldMaxY) {
this.y -= worldMaxY;
}
}
if (this.z < 1) {
this.z = MAXZ;
}
else {
if (this.z > MAXZ) {
this.z = 1;
}
}
}
// Point of View is in the center of the x, y plane with z = SCREENZ, looking into the world, so translate each x, y of coordinate to center of
// world. sMaxWidth is maxWidth of viewport. sMaxHeight is maxHeight of viewport.
this.project = function (sMaxWidth, sMaxHeight) {
var transX = this.x - (worldMaxX / 2);
var transY = this.y - (worldMaxY / 2);
this.projectedX = Math.floor((Math.floor(transX * SCREENZ) / this.z) + (sMaxWidth / 2));
this.projectedY = Math.floor((Math.floor(transY * SCREENZ) / this.z) + (sMaxHeight / 2));
this.renderStar = ((this.projectedX >= 0) && (this.projectedX <= sMaxWidth) && (this.projectedY >= 0) && (this.projectedY <= sMaxHeight));
}
}
</script>
</head>
<body style="background-color:#000;">
<div id="fbDiv">
</div>
<script>
init();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment