feat: create 404 page
This commit is contained in:
parent
b5d1d771c6
commit
aa9374bef4
148
src/pages/404.astro
Normal file
148
src/pages/404.astro
Normal file
@ -0,0 +1,148 @@
|
||||
---
|
||||
import Button from "@components/Button.astro";
|
||||
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||
---
|
||||
|
||||
<script>
|
||||
const STAR_COUNT = 10000;
|
||||
|
||||
let width: number;
|
||||
let height: number;
|
||||
const canvas = document.getElementById("canvas") as HTMLCanvasElement;
|
||||
let previousTime: number;
|
||||
|
||||
interface Star {
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
}
|
||||
|
||||
export const clear = (
|
||||
context: CanvasRenderingContext2D | null,
|
||||
canvas: HTMLCanvasElement
|
||||
) => {
|
||||
if (context) context.fillStyle = "#04000d";
|
||||
context?.fillRect(0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
export const drawPixel = (
|
||||
context: CanvasRenderingContext2D | null,
|
||||
x: number,
|
||||
y: number,
|
||||
brightness: number
|
||||
) => {
|
||||
const intensity = brightness * 255;
|
||||
if (context)
|
||||
context.fillStyle = `rgb(${intensity}, ${intensity}, ${intensity})`;
|
||||
context?.fillRect(x, y, 2, 2);
|
||||
};
|
||||
|
||||
export const moveStars = (stars: Star[], distance: number) => {
|
||||
stars.forEach((star) => {
|
||||
star.z = star.z <= 1 ? star.z + 1000 : star.z - distance;
|
||||
});
|
||||
};
|
||||
|
||||
const stars = Array.from({ length: STAR_COUNT }, () => ({
|
||||
x: Math.random() * 1600 - 800,
|
||||
y: Math.random() * 900 - 450,
|
||||
z: Math.random() * 1000,
|
||||
}));
|
||||
|
||||
const setCanvasExtents = () => {
|
||||
width = document.body.clientWidth;
|
||||
height = document.body.clientHeight;
|
||||
canvas.width = width;
|
||||
canvas.height = height;
|
||||
};
|
||||
|
||||
setCanvasExtents();
|
||||
|
||||
addEventListener("resize", () => {
|
||||
setCanvasExtents();
|
||||
});
|
||||
|
||||
const context = canvas.getContext("2d");
|
||||
|
||||
const tick = (time: number) => {
|
||||
let elapsed = time - previousTime;
|
||||
previousTime = time;
|
||||
|
||||
moveStars(stars, elapsed * 0.05);
|
||||
|
||||
clear(context, canvas);
|
||||
|
||||
const centerX = width / 2;
|
||||
const centerY = height / 2;
|
||||
|
||||
stars.forEach((star) => {
|
||||
const x = centerX + star.x / (star.z * 0.001);
|
||||
const y = centerY + star.y / (star.z * 0.001);
|
||||
|
||||
if (x >= 0 && x <= width && y >= 0 && y <= height) {
|
||||
const d = star.z / 1000.0;
|
||||
const b = 1 - d * d;
|
||||
|
||||
drawPixel(context, x, y, b);
|
||||
}
|
||||
});
|
||||
|
||||
requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
const init = (time: number) => {
|
||||
previousTime = time;
|
||||
requestAnimationFrame(tick);
|
||||
};
|
||||
|
||||
requestAnimationFrame(init);
|
||||
</script>
|
||||
|
||||
<BaseLayout title="404">
|
||||
<section class="error-404">
|
||||
<canvas id="canvas" class="starfield"></canvas>
|
||||
<div class="content">
|
||||
<h2 class="subheading subheading--mono">
|
||||
Error 404. Simulation disengaged. Critical cube disruption. Course
|
||||
correcting...
|
||||
</h2>
|
||||
<div class="button__container">
|
||||
<a href="/">
|
||||
<Button>reboot</Button>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
color: white;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.error-404 {
|
||||
height: 100vh;
|
||||
background-color: black;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.error-404 .starfield {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.error-404 .content {
|
||||
z-index: 1;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: calc(2 * var(--base-spacing));
|
||||
align-items: center;
|
||||
gap: calc(2 * var(--base-spacing));
|
||||
max-width: 40rem;
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user