What is Nostr?
ภ๏รtг๏ภคยt
npub1wl8…n8lu
2025-03-17 21:29:32

ภ๏รtг๏ภคยt on Nostr: I did it! My 1st successful build of something nostr related! 😭😭😭 So proud ...

I did it! My 1st successful build of something nostr related! 😭😭😭 So proud of myself! 🫂💜
The windows pipe Screensaver, but it only moves when zaped.


```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nostr Zap Pipes</title>
<style>
body {
margin: 0;
overflow: hidden;
background: black;
}
canvas {
display: block;
}
</style>
</head>
<body>
<canvas id="pipesCanvas"></canvas>
<script type="module">
import { SimplePool } from "https://esm.sh/nostr-tools";;

const canvas = document.getElementById("pipesCanvas");
const ctx = canvas.getContext("2d");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

const GRID_SIZE = 20;

function randomColor() {
const colors = ["red", "blue", "green", "yellow", "cyan", "magenta", "white", "orange"];
return colors[Math.floor(Math.random() * colors.length)];
}

class Pipe {
constructor(x, y) {
this.segments = [{ x, y }];
this.color = randomColor();
this.direction = Math.floor(Math.random() * 4);
}

willHitEdge(newX, newY) {
return newX < 0 || newX >= canvas.width || newY < 0 || newY >= canvas.height;
}

adjustDirection() {
let safeDirections = [0, 1, 2, 3].filter(dir => {
let testX = this.segments[this.segments.length - 1].x;
let testY = this.segments[this.segments.length - 1].y;

switch (dir) {
case 0: testY -= GRID_SIZE; break;
case 1: testX += GRID_SIZE; break;
case 2: testY += GRID_SIZE; break;
case 3: testX -= GRID_SIZE; break;
}

return !this.willHitEdge(testX, testY);
});

if (safeDirections.length > 0) {
this.direction = safeDirections[Math.floor(Math.random() * safeDirections.length)];
}
}

grow() {
const lastSegment = this.segments[this.segments.length - 1];
let newX = lastSegment.x;
let newY = lastSegment.y;

switch (this.direction) {
case 0: newY -= GRID_SIZE; break;
case 1: newX += GRID_SIZE; break;
case 2: newY += GRID_SIZE; break;
case 3: newX -= GRID_SIZE; break;
}

if (this.willHitEdge(newX, newY)) {
this.adjustDirection();
return;
}

if (Math.random() < 0.33) {
this.direction = Math.floor(Math.random() * 4);
}

this.segments.push({ x: newX, y: newY });
}

draw() {
ctx.fillStyle = this.color;
this.segments.forEach(segment => {
ctx.fillRect(segment.x, segment.y, GRID_SIZE, GRID_SIZE);
ctx.strokeStyle = "black";
ctx.strokeRect(segment.x, segment.y, GRID_SIZE, GRID_SIZE);
});
}
}

let pipes = [];

function drawPipes() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
pipes.forEach(pipe => pipe.draw());
}

function startPipes(numPipes = 5) {
for (let i = 0; i < numPipes; i++) {
const startX = Math.floor(Math.random() * (canvas.width / GRID_SIZE)) * GRID_SIZE;
const startY = Math.floor(Math.random() * (canvas.height / GRID_SIZE)) * GRID_SIZE;
pipes.push(new Pipe(startX, startY));
}
drawPipes();
}

startPipes(5);

const pool = new SimplePool();
const relays = [
"wss://nos.lol",
"wss://relay.nostr.band",
"wss://relay.damus.io"
];

let lastZapId = null;

function listenForZaps() {
console.log("📡 Subscribing to zaps...");

const sub = pool.subscribeMany(relays, [
{
kinds: [9735],
since: Math.floor(Date.now() / 1000)
}
], {
onevent(event) {
if (event.id === lastZapId) return;
lastZapId = event.id;

console.log("⚡ New Zap received!", event);


pipes.forEach(pipe => pipe.grow());
drawPipes();
},
oneose() {
console.log("End of stored events");
},
onerror(err) {
console.error("Subscription error:", err);
}
});
}

listenForZaps();
</script>
</body>
</html>

```
Author Public Key
npub1wl89d7yazg500lehg08p45dj2jzhhyqg2erj067458e3wd30djns4zn8lu