<!DOCTYPE html>
<html>
<head>
<title>Tunnel</title>
<meta name="category" content="Space">
<style>
body { margin: 0; background-color: #000; overflow: hidden; }
canvas { display: block; }
</style>
</head>
<body>
<canvas id="tunnelCanvas"></canvas>
<script>
const canvas = document.getElementById('tunnelCanvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const numLines = 200;
const lines = [];
let speed = 2;
let rotation = 0;
class Line {
constructor() {
this.reset();
}
reset() {
this.x = 0;
this.y = 0;
this.z = Math.random() * canvas.width;
this.angle = Math.random() * Math.PI * 2;
this.radius = Math.random() * (canvas.width / 4) + (canvas.width / 8);
}
update() {
this.z -= speed;
if (this.z < 1) {
this.reset();
}
}
draw() {
const scale = canvas.width / this.z;
const x2d = Math.cos(this.angle + rotation) * this.radius * scale + canvas.width / 2;
const y2d = Math.sin(this.angle + rotation) * this.radius * scale + canvas.height / 2;
const prev_scale = canvas.width / (this.z + speed * 20);
const prev_x2d = Math.cos(this.angle + rotation) * this.radius * prev_scale + canvas.width / 2;
const prev_y2d = Math.sin(this.angle + rotation) * this.radius * prev_scale + canvas.height / 2;
const brightness = 1 - this.z / canvas.width;
ctx.beginPath();
ctx.moveTo(prev_x2d, prev_y2d);
ctx.lineTo(x2d, y2d);
ctx.strokeStyle = `rgba(200, 220, 255, ${brightness * 0.7})`;
ctx.lineWidth = scale * 1.5;
ctx.stroke();
}
}
function init() {
for (let i = 0; i < numLines; i++) {
lines.push(new Line());
}
}
function animate() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
rotation += 0.001;
lines.forEach(line => {
line.update();
line.draw();
});
requestAnimationFrame(animate);
}
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
lines.length = 0;
init();
});
init();
if (typeof window.isThumbnail !== 'undefined' && window.isThumbnail) {
for(let i=0; i<120; i++) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
rotation += 0.001;
lines.forEach(line => {
line.update();
line.draw();
});
}
} else {
animate();
}
</script>
</body>
</html>
<canvas id="tunnelCanvas"></canvas>
body { margin: 0; background-color: #000; overflow: hidden; }
canvas { display: block; }
const canvas = document.getElementById('tunnelCanvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const numLines = 200;
const lines = [];
let speed = 2;
let rotation = 0;
class Line {
constructor() {
this.reset();
}
reset() {
this.x = 0;
this.y = 0;
this.z = Math.random() * canvas.width;
this.angle = Math.random() * Math.PI * 2;
this.radius = Math.random() * (canvas.width / 4) + (canvas.width / 8);
}
update() {
this.z -= speed;
if (this.z < 1) {
this.reset();
}
}
draw() {
const scale = canvas.width / this.z;
const x2d = Math.cos(this.angle + rotation) * this.radius * scale + canvas.width / 2;
const y2d = Math.sin(this.angle + rotation) * this.radius * scale + canvas.height / 2;
const prev_scale = canvas.width / (this.z + speed * 20);
const prev_x2d = Math.cos(this.angle + rotation) * this.radius * prev_scale + canvas.width / 2;
const prev_y2d = Math.sin(this.angle + rotation) * this.radius * prev_scale + canvas.height / 2;
const brightness = 1 - this.z / canvas.width;
ctx.beginPath();
ctx.moveTo(prev_x2d, prev_y2d);
ctx.lineTo(x2d, y2d);
ctx.strokeStyle = `rgba(200, 220, 255, ${brightness * 0.7})`;
ctx.lineWidth = scale * 1.5;
ctx.stroke();
}
}
function init() {
for (let i = 0; i < numLines; i++) {
lines.push(new Line());
}
}
function animate() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
rotation += 0.001;
lines.forEach(line => {
line.update();
line.draw();
});
requestAnimationFrame(animate);
}
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
lines.length = 0;
init();
});
init();
if (typeof window.isThumbnail !== 'undefined' && window.isThumbnail) {
for(let i=0; i<120; i++) {
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
rotation += 0.001;
lines.forEach(line => {
line.update();
line.draw();
});
}
} else {
animate();
}