ColorPipesScreensaver / index.html
Remsky's picture
Update index.html
76d0fa7 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Windows Pipes Screensaver</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #000;
}
canvas {
display: block;
}
.controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(0, 0, 0, 0.7);
padding: 10px 20px;
border-radius: 8px;
color: white;
font-family: Arial, sans-serif;
display: flex;
gap: 15px;
align-items: center;
}
.controls button {
background-color: #0078d7;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.controls button:hover {
background-color: #005a9e;
}
.title {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
color: white;
font-family: 'Arial', sans-serif;
font-size: 24px;
text-shadow: 0 0 10px rgba(0, 120, 215, 0.7);
background-color: rgba(0, 0, 0, 0.5);
padding: 10px 20px;
border-radius: 8px;
}
.pipe-count {
display: flex;
align-items: center;
gap: 5px;
}
input[type="range"] {
width: 100px;
}
</style>
</head>
<body>
<div class="title">Windows Pipes Screensaver</div>
<canvas id="pipesCanvas"></canvas>
<div class="controls">
<div class="pipe-count">
<span>Pipe Count:</span>
<input type="range" id="pipeCount" min="5" max="50" value="15">
<span id="pipeCountValue">15</span>
</div>
<div class="pipe-count">
<span>Speed:</span>
<input type="range" id="speedControl" min="1" max="10" value="5">
<span id="speedValue">5</span>
</div>
<button id="colorBtn">Random Colors</button>
<button id="resetBtn">Reset</button>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('pipesCanvas');
const ctx = canvas.getContext('2d');
const pipeCountInput = document.getElementById('pipeCount');
const pipeCountValue = document.getElementById('pipeCountValue');
const speedControl = document.getElementById('speedControl');
const speedValue = document.getElementById('speedValue');
const colorBtn = document.getElementById('colorBtn');
const resetBtn = document.getElementById('resetBtn');
// Set canvas size
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);
// Pipe settings
let pipeCount = parseInt(pipeCountInput.value);
let speed = parseInt(speedControl.value);
let useRandomColors = false;
let pipes = [];
const colors = [
'#0078d7', '#107c10', '#e81123', '#ffb900',
'#881798', '#00b7c3', '#ff8c00', '#5c2d91'
];
// Pipe class
class Pipe {
constructor() {
this.reset();
this.color = colors[Math.floor(Math.random() * colors.length)];
}
reset() {
this.x = Math.random() * canvas.width;
this.y = Math.random() * canvas.height;
this.direction = Math.floor(Math.random() * 4); // 0: right, 1: down, 2: left, 3: up
this.length = 0;
this.maxLength = 50 + Math.random() * 100;
this.speed = 2 + Math.random() * 3;
this.bendCount = 0;
this.maxBends = 2 + Math.floor(Math.random() * 3);
}
update() {
const moveAmount = this.speed * (speed / 5);
switch(this.direction) {
case 0: // right
this.x += moveAmount;
break;
case 1: // down
this.y += moveAmount;
break;
case 2: // left
this.x -= moveAmount;
break;
case 3: // up
this.y -= moveAmount;
break;
}
this.length += moveAmount;
// Check if we should bend
if (this.length >= this.maxLength && this.bendCount < this.maxBends) {
this.length = 0;
this.bendCount++;
this.maxLength = 50 + Math.random() * 100;
// Randomly choose to turn left or right relative to current direction
if (Math.random() > 0.5) {
this.direction = (this.direction + 1) % 4;
} else {
this.direction = (this.direction - 1 + 4) % 4;
}
}
// Check if we should reset
if (this.x < 0 || this.x > canvas.width || this.y < 0 || this.y > canvas.height ||
(this.length >= this.maxLength && this.bendCount >= this.maxBends)) {
this.reset();
}
}
draw(ctx) {
ctx.strokeStyle = useRandomColors ?
`hsl(${Math.random() * 360}, 100%, 50%)` : this.color;
ctx.lineWidth = 8;
ctx.lineCap = 'round';
ctx.beginPath();
// Draw the pipe segment based on direction
switch(this.direction) {
case 0: // right
ctx.moveTo(this.x - this.length, this.y);
ctx.lineTo(this.x, this.y);
break;
case 1: // down
ctx.moveTo(this.x, this.y - this.length);
ctx.lineTo(this.x, this.y);
break;
case 2: // left
ctx.moveTo(this.x + this.length, this.y);
ctx.lineTo(this.x, this.y);
break;
case 3: // up
ctx.moveTo(this.x, this.y + this.length);
ctx.lineTo(this.x, this.y);
break;
}
ctx.stroke();
// Draw the pipe joint
ctx.fillStyle = useRandomColors ?
`hsl(${Math.random() * 360}, 100%, 50%)` : this.color;
ctx.beginPath();
ctx.arc(this.x, this.y, 5, 0, Math.PI * 2);
ctx.fill();
}
}
// Initialize pipes
function initPipes() {
pipes = [];
for (let i = 0; i < pipeCount; i++) {
pipes.push(new Pipe());
}
}
initPipes();
// Animation loop
function animate() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (let pipe of pipes) {
pipe.update();
pipe.draw(ctx);
}
requestAnimationFrame(animate);
}
animate();
// Event listeners
pipeCountInput.addEventListener('input', () => {
pipeCount = parseInt(pipeCountInput.value);
pipeCountValue.textContent = pipeCount;
initPipes();
});
speedControl.addEventListener('input', () => {
speed = parseInt(speedControl.value);
speedValue.textContent = speed;
});
colorBtn.addEventListener('click', () => {
useRandomColors = !useRandomColors;
colorBtn.textContent = useRandomColors ? 'Solid Colors' : 'Random Colors';
});
resetBtn.addEventListener('click', () => {
initPipes();
});
// Mouse movement to reset position (like a real screensaver)
let mouseX = 0;
let mouseY = 0;
let lastMouseMove = Date.now();
document.addEventListener('mousemove', (e) => {
mouseX = e.clientX;
mouseY = e.clientY;
lastMouseMove = Date.now();
// If mouse is moved, reset all pipes
if (Date.now() - lastMouseMove < 100) {
for (let pipe of pipes) {
pipe.reset();
}
}
});
});
</script>
</body>
</html>