| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
- <title>nodes</title>
- <style>
- :root {
- --node-color: #ff00ff;
- --bg-1: #05010a;
- --bg-2: #13051d;
- --line-alpha: 0.28;
- }
- * {
- box-sizing: border-box;
- }
- html, body {
- margin: 0;
- width: 100%;
- height: 100%;
- overflow: hidden;
- background:
- radial-gradient(circle at 20% 20%, rgba(255, 0, 255, 0.08), transparent 30%),
- radial-gradient(circle at 80% 30%, rgba(255, 0, 255, 0.06), transparent 24%),
- linear-gradient(160deg, var(--bg-1), var(--bg-2));
- font-family: Inter, Arial, sans-serif;
- }
- canvas {
- display: block;
- width: 100vw;
- height: 100vh;
- cursor: crosshair;
- }
- </style>
- </head>
- <body>
- <canvas id="network"></canvas>
-
- <script>
- const canvas = document.getElementById('network');
- const ctx = canvas.getContext('2d');
- const CONFIG = {
- nodeCount: 90,
- nodeColor: '#ff00ff',
- nodeRadiusMin: 2.2,
- nodeRadiusMax: 5.5,
- linkDistance: 150,
- mouseInfluence: 190,
- attractionStrength: 0.02,
- returnStrength: 0.012,
- friction: 0.92,
- pulseSpeed: 0.0025,
- wobble: 0.18,
- };
- let width = 0;
- let height = 0;
- let dpr = Math.min(window.devicePixelRatio || 1, 2);
- let time = 0;
- const mouse = {
- x: 0,
- y: 0,
- active: false,
- };
- class Node {
- constructor() {
- this.homeX = Math.random() * width;
- this.homeY = Math.random() * height;
- this.x = this.homeX;
- this.y = this.homeY;
- this.vx = 0;
- this.vy = 0;
- this.radius = CONFIG.nodeRadiusMin + Math.random() * (CONFIG.nodeRadiusMax - CONFIG.nodeRadiusMin);
- this.seed = Math.random() * Math.PI * 2;
- }
- update(t) {
- const dxHome = this.homeX - this.x;
- const dyHome = this.homeY - this.y;
- this.vx += dxHome * CONFIG.returnStrength;
- this.vy += dyHome * CONFIG.returnStrength;
- const wobbleX = Math.cos(t * CONFIG.pulseSpeed + this.seed) * CONFIG.wobble;
- const wobbleY = Math.sin(t * CONFIG.pulseSpeed * 0.85 + this.seed) * CONFIG.wobble;
- this.vx += wobbleX * 0.03;
- this.vy += wobbleY * 0.03;
- if (mouse.active) {
- const dx = mouse.x - this.x;
- const dy = mouse.y - this.y;
- const dist = Math.hypot(dx, dy) || 0.0001;
- if (dist < CONFIG.mouseInfluence) {
- const force = (1 - dist / CONFIG.mouseInfluence) * CONFIG.attractionStrength * 28;
- this.vx += (dx / dist) * force;
- this.vy += (dy / dist) * force;
- }
- }
- this.vx *= CONFIG.friction;
- this.vy *= CONFIG.friction;
- this.x += this.vx;
- this.y += this.vy;
- }
- draw(t) {
- const pulse = 1 + Math.sin(t * 0.004 + this.seed) * 0.16;
- const r = this.radius * pulse;
- ctx.beginPath();
- ctx.arc(this.x, this.y, r, 0, Math.PI * 2);
- ctx.fillStyle = CONFIG.nodeColor;
- ctx.shadowColor = CONFIG.nodeColor;
- ctx.shadowBlur = 16;
- ctx.fill();
- ctx.shadowBlur = 0;
- ctx.beginPath();
- ctx.arc(this.x, this.y, r * 2.1, 0, Math.PI * 2);
- ctx.fillStyle = 'rgba(255, 0, 255, 0.05)';
- ctx.fill();
- }
- }
- let nodes = [];
- function resize() {
- width = window.innerWidth;
- height = window.innerHeight;
- dpr = Math.min(window.devicePixelRatio || 1, 2);
- canvas.width = width * dpr;
- canvas.height = height * dpr;
- canvas.style.width = width + 'px';
- canvas.style.height = height + 'px';
- ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
- nodes = Array.from({ length: CONFIG.nodeCount }, () => new Node());
- }
- function drawLinks() {
- for (let i = 0; i < nodes.length; i++) {
- for (let j = i + 1; j < nodes.length; j++) {
- const a = nodes[i];
- const b = nodes[j];
- const dx = b.x - a.x;
- const dy = b.y - a.y;
- const dist = Math.hypot(dx, dy);
- if (dist < CONFIG.linkDistance) {
- const alpha = (1 - dist / CONFIG.linkDistance) * 0.65;
- ctx.beginPath();
- ctx.moveTo(a.x, a.y);
- ctx.lineTo(b.x, b.y);
- ctx.strokeStyle = `rgba(255, 0, 255, ${alpha * 0.65})`;
- ctx.lineWidth = 1;
- ctx.stroke();
- }
- }
- }
- }
- function animate(timestamp) {
- time = timestamp;
- ctx.clearRect(0, 0, width, height);
- const gradient = ctx.createRadialGradient(
- mouse.active ? mouse.x : width * 0.5,
- mouse.active ? mouse.y : height * 0.5,
- 0,
- width * 0.5,
- height * 0.5,
- Math.max(width, height) * 0.7
- );
- gradient.addColorStop(0, 'rgba(255, 0, 255, 0.06)');
- gradient.addColorStop(1, 'rgba(255, 0, 255, 0)');
- ctx.fillStyle = gradient;
- ctx.fillRect(0, 0, width, height);
- nodes.forEach(node => node.update(timestamp));
- drawLinks();
- nodes.forEach(node => node.draw(timestamp));
- requestAnimationFrame(animate);
- }
- window.addEventListener('mousemove', (event) => {
- mouse.x = event.clientX;
- mouse.y = event.clientY;
- mouse.active = true;
- });
- window.addEventListener('touchmove', (event) => {
- if (event.touches[0]) {
- mouse.x = event.touches[0].clientX;
- mouse.y = event.touches[0].clientY;
- mouse.active = true;
- }
- }, { passive: true });
- window.addEventListener('mouseleave', () => {
- mouse.active = false;
- });
- window.addEventListener('touchend', () => {
- mouse.active = false;
- });
- window.addEventListener('resize', resize);
- resize();
- requestAnimationFrame(animate);
- </script>
- </body>
- </html>
|