Created
March 11, 2023 15:53
-
-
Save charafmrah/51db55e98a8a9c5f9a687e2fd0532faf to your computer and use it in GitHub Desktop.
Starfield
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div id="starfield" class="absolute inset-0"> | |
<canvas id="starfield-canvas"></canvas> | |
</div> | |
<script> | |
import invariant from "tiny-invariant"; | |
const COUNT = 800; | |
const SPEED = 0.1; | |
class Star { | |
x: number; | |
y: number; | |
z: number; | |
xPrev: number; | |
yPrev: number; | |
constructor(x = 0, y = 0, z = 0) { | |
this.x = x; | |
this.y = y; | |
this.z = z; | |
this.xPrev = x; | |
this.yPrev = y; | |
} | |
update(width: number, height: number, speed: number) { | |
this.xPrev = this.x; | |
this.yPrev = this.y; | |
this.z += speed * 0.0675; | |
this.x += this.x * (speed * 0.0225) * this.z; | |
this.y += this.y * (speed * 0.0225) * this.z; | |
if ( | |
this.x > width / 2 || | |
this.x < -width / 2 || | |
this.y > height / 2 || | |
this.y < -height / 2 | |
) { | |
this.x = Math.random() * width - width / 2; | |
this.y = Math.random() * height - height / 2; | |
this.xPrev = this.x; | |
this.yPrev = this.y; | |
this.z = 0; | |
} | |
} | |
draw(ctx: CanvasRenderingContext2D) { | |
ctx.lineWidth = this.z; | |
ctx.beginPath(); | |
ctx.moveTo(this.x, this.y); | |
ctx.lineTo(this.xPrev, this.yPrev); | |
ctx.stroke(); | |
} | |
} | |
const stars = Array.from({ length: COUNT }, () => new Star(0, 0, 0)); | |
let rafId = 0; | |
const canvas = document.querySelector( | |
"#starfield-canvas" | |
) as HTMLCanvasElement; | |
invariant(canvas, "canvas should not be null"); | |
const ctx = canvas.getContext("2d"); | |
const container = document.querySelector("#starfield") as HTMLElement; | |
invariant(container, "container should not be null"); | |
const resizeObserver = new ResizeObserver(setup); | |
resizeObserver.observe(container); | |
function setup() { | |
invariant(ctx, "canvas context should not be null"); | |
rafId > 0 && cancelAnimationFrame(rafId); | |
const { clientWidth: width, clientHeight: height } = container; | |
const dpr = window.devicePixelRatio || 1; | |
canvas.width = width * dpr; | |
canvas.height = height * dpr; | |
canvas.style.width = `${width}px`; | |
canvas.style.height = `${height}px`; | |
ctx.scale(dpr, dpr); | |
for (const star of stars) { | |
star.x = Math.random() * width - width / 2; | |
star.y = Math.random() * height - height / 2; | |
star.z = 0; | |
} | |
ctx.translate(width / 2, height / 2); | |
ctx.fillStyle = "rgba(0, 0, 0, 0.4)"; | |
ctx.strokeStyle = "white"; | |
rafId = requestAnimationFrame(frame); | |
} | |
function frame() { | |
invariant(ctx, "canvas context should not be null"); | |
const { clientWidth: width, clientHeight: height } = container; | |
for (const star of stars) { | |
star.update(width, height, SPEED); | |
star.draw(ctx); | |
} | |
ctx.fillRect(-width / 2, -height / 2, width, height); | |
rafId = requestAnimationFrame(frame); | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment