← back to Model Arena

data/artifacts/097db196034e/kimi.html

353 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI Agent Constellation</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            background: #000;
            font-family: 'Courier New', monospace;
        }
        canvas {
            display: block;
            background: radial-gradient(ellipse at center, #0a0e27 0%, #000000 100%);
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

let width, height;
let mouseX = 0, mouseY = 0;
let hoveredNode = null;

function resize() {
    width = canvas.width = window.innerWidth;
    height = canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();

// Starfield background
const stars = [];
for (let i = 0; i < 200; i++) {
    stars.push({
        x: Math.random() * window.innerWidth,
        y: Math.random() * window.innerHeight,
        size: Math.random() * 1.5,
        blink: Math.random() * Math.PI * 2
    });
}

class Node {
    constructor(id, x, y) {
        this.id = id;
        this.x = x;
        this.y = y;
        this.vx = (Math.random() - 0.5) * 0.5;
        this.vy = (Math.random() - 0.5) * 0.5;
        this.radius = 5 + Math.random() * 3;
        this.mass = this.radius;
        this.pulse = Math.random() * Math.PI * 2;
    }

    update() {
        this.x += this.vx;
        this.y += this.vy;
        
        // Gentle drift damping
        this.vx *= 0.98;
        this.vy *= 0.98;
        
        // Random gentle drift
        this.vx += (Math.random() - 0.5) * 0.02;
        this.vy += (Math.random() - 0.5) * 0.02;
        
        // Boundary containment
        if (this.x < 50) this.vx += 0.05;
        if (this.x > width - 50) this.vx -= 0.05;
        if (this.y < 50) this.vy += 0.05;
        if (this.y > height - 50) this.vy -= 0.05;
        
        this.pulse += 0.05;
    }

    draw(ctx, isHovered, isNeighbor) {
        const glow = isHovered ? 30 : (isNeighbor ? 20 : 10);
        const alpha = isHovered ? 1 : (isNeighbor ? 0.8 : 0.6);
        
        // Outer glow
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius * 2, 0, Math.PI * 2);
        ctx.fillStyle = `rgba(0, 255, 255, ${alpha * 0.1})`;
        ctx.fill();
        
        // Core
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = isHovered ? '#fff' : '#00ffff';
        ctx.shadowBlur = glow;
        ctx.shadowColor = '#00ffff';
        ctx.fill();
        ctx.shadowBlur = 0;
        
        // Label
        if (isHovered || isNeighbor) {
            ctx.fillStyle = '#00ffff';
            ctx.font = '11px monospace';
            ctx.fillText(`AGENT-${this.id}`, this.x + 12, this.y + 4);
        }
    }
}

class Edge {
    constructor(a, b) {
        this.a = a;
        this.b = b;
        this.restLength = 120 + Math.random() * 80;
        this.messages = [];
        this.lastMessageTime = Math.random() * 100;
    }

    update() {
        // Spring force
        const dx = this.b.x - this.a.x;
        const dy = this.b.y - this.a.y;
        const dist = Math.sqrt(dx * dx + dy * dy) || 1;
        const force = (dist - this.restLength) * 0.0002;
        
        const fx = (dx / dist) * force;
        const fy = (dy / dist) * force;
        
        this.a.vx += fx / this.a.mass;
        this.a.vy += fy / this.a.mass;
        this.b.vx -= fx / this.b.mass;
        this.b.vy -= fy / this.b.mass;
        
        // Message spawning
        this.lastMessageTime++;
        if (this.lastMessageTime > 50 + Math.random() * 100) {
            this.messages.push({
                progress: 0,
                speed: 0.01 + Math.random() * 0.02,
                intensity: 1
            });
            this.lastMessageTime = 0;
        }
        
        // Update messages
        for (let i = this.messages.length - 1; i >= 0; i--) {
            const msg = this.messages[i];
            msg.progress += msg.speed;
            if (msg.progress >= 1) {
                this.messages.splice(i, 1);
            }
        }
    }

    draw(ctx, isHighlighted) {
        const dx = this.b.x - this.a.x;
        const dy = this.b.y - this.a.y;
        
        // Base connection
        ctx.beginPath();
        ctx.moveTo(this.a.x, this.a.y);
        ctx.lineTo(this.b.x, this.b.y);
        ctx.strokeStyle = isHighlighted ? 'rgba(0, 255, 255, 0.3)' : 'rgba(0, 255, 255, 0.08)';
        ctx.lineWidth = isHighlighted ? 2 : 1;
        ctx.stroke();
        
        // Traveling messages
        for (const msg of this.messages) {
            const x = this.a.x + dx * msg.progress;
            const y = this.a.y + dy * msg.progress;
            
            // Message glow
            ctx.beginPath();
            ctx.arc(x, y, 4, 0, Math.PI * 2);
            ctx.fillStyle = '#00ffff';
            ctx.shadowBlur = 15;
            ctx.shadowColor = '#00ffff';
            ctx.fill();
            ctx.shadowBlur = 0;
            
            // Trail
            ctx.beginPath();
            const tailX = this.a.x + dx * Math.max(0, msg.progress - 0.1);
            const tailY = this.a.y + dy * Math.max(0, msg.progress - 0.1);
            ctx.moveTo(tailX, tailY);
            ctx.lineTo(x, y);
            ctx.strokeStyle = 'rgba(0, 255, 255, 0.6)';
            ctx.lineWidth = 2;
            ctx.stroke();
        }
    }
}

// Initialize graph
const nodes = [];
const edges = [];
const nodeCount = 24;

// Create nodes in circle initially to ensure spread
for (let i = 0; i < nodeCount; i++) {
    const angle = (i / nodeCount) * Math.PI * 2;
    const r = Math.min(width, height) * 0.3;
    const x = width / 2 + Math.cos(angle) * r;
    const y = height / 2 + Math.sin(angle) * r;
    nodes.push(new Node(i, x, y));
}

// Create edges - ensure connected graph with random extra connections
for (let i = 0; i < nodeCount; i++) {
    // Connect to next node (ring)
    edges.push(new Edge(nodes[i], nodes[(i + 1) % nodeCount]));
    
    // Random additional connections
    const extra = 1 + Math.floor(Math.random() * 2);
    for (let j = 0; j < extra; j++) {
        const target = Math.floor(Math.random() * nodeCount);
        if (target !== i && target !== (i + 1) % nodeCount && target !== (i - 1 + nodeCount) % nodeCount) {
            // Check duplicate
            const exists = edges.some(e => 
                (e.a === nodes[i] && e.b === nodes[target]) ||
                (e.a === nodes[target] && e.b === nodes[i])
            );
            if (!exists) {
                edges.push(new Edge(nodes[i], nodes[target]));
            }
        }
    }
}

// Build adjacency for hover highlighting
const adjacency = new Map();
nodes.forEach(n => adjacency.set(n, new Set()));
edges.forEach(e => {
    adjacency.get(e.a).add(e.b);
    adjacency.get(e.b).add(e.a);
});

// Mouse tracking
canvas.addEventListener('mousemove', (e) => {
    mouseX = e.clientX;
    mouseY = e.clientY;
    
    hoveredNode = null;
    for (const node of nodes) {
        const dx = mouseX - node.x;
        const dy = mouseY - node.y;
        if (dx * dx + dy * dy < 100) {
            hoveredNode = node;
            break;
        }
    }
});

function updatePhysics() {
    // Repulsion between all nodes
    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 distSq = dx * dx + dy * dy;
            if (distSq === 0) continue;
            
            const dist = Math.sqrt(distSq);
            const force = 3000 / (distSq + 100); // Softened repulsion
            
            const fx = (dx / dist) * force;
            const fy = (dy / dist) * force;
            
            a.vx -= fx / a.mass;
            a.vy -= fy / a.mass;
            b.vx += fx / b.mass;
            b.vy += fy / b.mass;
        }
    }
    
    // Center attraction (keep in view)
    for (const node of nodes) {
        const dx = (width / 2) - node.x;
        const dy = (height / 2) - node.y;
        node.vx += dx * 0.0001;
        node.vy += dy * 0.0001;
    }
    
    // Update edges
    for (const edge of edges) {
        edge.update();
    }
    
    // Update nodes
    for (const node of nodes) {
        node.update();
    }
}

function draw() {
    // Clear
    ctx.fillStyle = '#000005';
    ctx.fillRect(0, 0, width, height);
    
    // Draw stars
    ctx.fillStyle = '#fff';
    for (const star of stars) {
        star.blink += 0.02;
        const alpha = 0.3 + Math.sin(star.blink) * 0.3;
        ctx.globalAlpha = alpha;
        ctx.fillRect(star.x, star.y, star.size, star.size);
    }
    ctx.globalAlpha = 1;
    
    // Determine highlighted elements
    const highlightedNodes = new Set();
    const highlightedEdges = new Set();
    
    if (hoveredNode) {
        highlightedNodes.add(hoveredNode);
        adjacency.get(hoveredNode).forEach(n => highlightedNodes.add(n));
        
        edges.forEach(e => {
            if (e.a === hoveredNode || e.b === hoveredNode) {
                highlightedEdges.add(e);
            }
        });
    }
    
    // Draw edges
    for (const edge of edges) {
        edge.draw(ctx, highlightedEdges.has(edge));
    }
    
    // Draw nodes
    for (const node of nodes) {
        const isHovered = node === hoveredNode;
        const isNeighbor = highlightedNodes.has(node) && !isHovered;
        node.draw(ctx, isHovered, isNeighbor);
    }
    
    // Instructions
    ctx.fillStyle = 'rgba(0, 255, 255, 0.5)';
    ctx.font = '12px monospace';
    ctx.fillText('HOVER TO SCAN NEIGHBORS', 20, height - 20);
}

function loop() {
    updatePhysics();
    draw();
    requestAnimationFrame(loop);
}

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