Compare commits

...

2 Commits

3 changed files with 228 additions and 86 deletions

Binary file not shown.

View File

@@ -49,35 +49,37 @@ class NeuralNetworkBackground {
this.animationFrameId = null;
this.isDarkMode = true; // Always use dark mode for the background
// Colors - Updated to be more subtle
// Colors - Updated for intense visibility and neural effect
this.darkModeColors = {
background: '#050a14', // Darker blue-black background
nodeColor: '#4a5568', // Darker nodes for subtlety
nodePulse: '#718096', // Subtle blue pulse
connectionColor: '#2d3748', // Darker connections
flowColor: '#4a88ff80' // Semi-transparent flow highlight
background: '#030610', // Noch dunklerer Hintergrund für besseren Kontrast
nodeColor: '#88a5ff', // Hellere, leuchtende Knoten
nodePulse: '#c0d5ff', // Strahlend helles Pulsieren
connectionColor: '#5a6ca8', // Hellere, sichtbarere Verbindungen
flowColor: '#90c8ffee' // Sehr leuchtende, fast undurchsichtige Flüsse
};
this.lightModeColors = {
background: '#f9fafb',
nodeColor: '#7c3aed',
nodePulse: '#8b5cf6',
connectionColor: '#a78bfa',
flowColor: '#c4b5fd'
nodeColor: '#8c4aff',
nodePulse: '#ab7cff',
connectionColor: '#b798ff',
flowColor: '#d4c5ff'
};
// Config - Updated to be more subtle, efficient, and elegant
// Config - Drastisch verstärkt für strahlende Animationen und neuronale Vernetzung
this.config = {
nodeCount: 70, // Reduced node count for better performance
nodeSize: 0.6, // Smaller nodes for subtlety
nodeVariation: 0.3, // Less variation for uniformity
connectionDistance: 150, // Shorter connections for cleaner look
connectionOpacity: 0.15, // More subtle connections
animationSpeed: 0.04, // Slower, more elegant movement
pulseSpeed: 0.002, // Very slow pulse for subtlety
flowSpeed: 0.4, // Slower flow animations
flowDensity: 0.0008, // Less frequent flow animations
flowLength: 0.15 // Shorter flow animations
nodeCount: 120, // Viel mehr Knoten für ein dichtes Netzwerk
nodeSize: 1.4, // Größere Knoten für mehr Sichtbarkeit
nodeVariation: 0.6, // Mehr Variation für organisches Aussehen
connectionDistance: 220, // Deutlich längere Verbindungen für mehr Vernetzung
connectionOpacity: 0.4, // Wesentlich stärkere Verbindungen
animationSpeed: 0.08, // Schnellere Bewegung
pulseSpeed: 0.006, // Schnelleres Pulsieren für lebendiges Aussehen
flowSpeed: 0.8, // Schnellere Flussanimationen
flowDensity: 0.005, // Viel mehr Flussanimationen
flowLength: 0.25, // Längere Flussanimationen
maxConnections: 6, // NEW: Neue Eigenschaft für mehr neuronale Verbindungen pro Knoten
clusteringFactor: 0.3 // NEW: Erzeugt Cluster wie in einem neuronalen Netzwerk
};
// Initialize
@@ -221,18 +223,60 @@ class NeuralNetworkBackground {
const width = this.canvas.width / (window.devicePixelRatio || 1);
const height = this.canvas.height / (window.devicePixelRatio || 1);
// Create nodes with random positions and properties
for (let i = 0; i < this.config.nodeCount; i++) {
const node = {
// Erstelle Cluster-Zentren für neuronale Netzwerkmuster
const clusterCount = Math.floor(5 + Math.random() * 4); // 5-8 Cluster
const clusters = [];
for (let i = 0; i < clusterCount; i++) {
clusters.push({
x: Math.random() * width,
y: Math.random() * height,
size: this.config.nodeSize + Math.random() * this.config.nodeVariation,
radius: 100 + Math.random() * 150
});
}
// Create nodes with random positions and properties
for (let i = 0; i < this.config.nodeCount; i++) {
// Entscheide, ob dieser Knoten zu einem Cluster gehört oder nicht
const useCluster = Math.random() < this.config.clusteringFactor;
let x, y;
if (useCluster && clusters.length > 0) {
// Wähle ein zufälliges Cluster
const cluster = clusters[Math.floor(Math.random() * clusters.length)];
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * cluster.radius;
// Platziere in der Nähe des Clusters mit einiger Streuung
x = cluster.x + Math.cos(angle) * distance;
y = cluster.y + Math.sin(angle) * distance;
// Stelle sicher, dass es innerhalb des Bildschirms bleibt
x = Math.max(0, Math.min(width, x));
y = Math.max(0, Math.min(height, y));
} else {
// Zufällige Position außerhalb von Clustern
x = Math.random() * width;
y = Math.random() * height;
}
// Bestimme die Knotengröße - wichtigere Knoten (in Clustern) sind größer
const nodeImportance = useCluster ? 1.2 : 0.8;
const size = this.config.nodeSize * nodeImportance + Math.random() * this.config.nodeVariation;
const node = {
x: x,
y: y,
size: size,
speed: {
x: (Math.random() - 0.5) * this.config.animationSpeed,
y: (Math.random() - 0.5) * this.config.animationSpeed
},
pulsePhase: Math.random() * Math.PI * 2, // Random starting phase
connections: []
connections: [],
isActive: Math.random() < 0.3, // Some nodes start active for neural firing effect
lastFired: 0, // For neural firing animation
firingRate: 1000 + Math.random() * 4000 // Random firing rate in ms
};
this.nodes.push(node);
@@ -248,23 +292,60 @@ class NeuralNetworkBackground {
const nodeA = this.nodes[i];
nodeA.connections = [];
for (let j = i + 1; j < this.nodes.length; j++) {
// Sortiere andere Knoten nach Entfernung für bevorzugte nahe Verbindungen
const potentialConnections = [];
for (let j = 0; j < this.nodes.length; j++) {
if (i === j) continue;
const nodeB = this.nodes[j];
const dx = nodeB.x - nodeA.x;
const dy = nodeB.y - nodeA.y;
const distance = Math.sqrt(dx * dx + dy * dy);
if (distance < this.config.connectionDistance) {
potentialConnections.push({
index: j,
distance: distance
});
}
}
// Sortiere nach Entfernung
potentialConnections.sort((a, b) => a.distance - b.distance);
// Wähle die nächsten N Verbindungen, maximal maxConnections
const maxConn = Math.min(
this.config.maxConnections,
potentialConnections.length,
1 + Math.floor(Math.random() * this.config.maxConnections)
);
for (let c = 0; c < maxConn; c++) {
const connection = potentialConnections[c];
const j = connection.index;
const nodeB = this.nodes[j];
const distance = connection.distance;
// Create weighted connection (closer = stronger)
const connectionStrength = Math.max(0, 1 - distance / this.config.connectionDistance);
const connOpacity = connectionStrength * this.config.connectionOpacity;
// Check if connection already exists
if (!this.connections.some(conn =>
(conn.from === i && conn.to === j) || (conn.from === j && conn.to === i)
)) {
// Create connection
const connection = {
this.connections.push({
from: i,
to: j,
distance: distance,
opacity: Math.max(0, 1 - distance / this.config.connectionDistance) * this.config.connectionOpacity,
hasFlow: false // Each connection can have a flow
};
opacity: connOpacity,
strength: connectionStrength,
hasFlow: false, // Each connection can have a flow
lastActivated: 0 // For neural firing animation
});
this.connections.push(connection);
nodeA.connections.push(j);
nodeB.connections.push(i);
}
@@ -280,42 +361,48 @@ class NeuralNetworkBackground {
// Update nodes
const width = this.canvas.width / (window.devicePixelRatio || 1);
const height = this.canvas.height / (window.devicePixelRatio || 1);
const now = Date.now();
// Update node positions - slower, more flowing movement
// Simulate neural firing
for (let i = 0; i < this.nodes.length; i++) {
const node = this.nodes[i];
// Move node with slight randomness for organic feel
node.speed.x += (Math.random() - 0.5) * 0.001;
node.speed.y += (Math.random() - 0.5) * 0.001;
// Check if node should fire based on its firing rate
if (now - node.lastFired > node.firingRate) {
node.isActive = true;
node.lastFired = now;
// Dampen speeds for stability
node.speed.x *= 0.99;
node.speed.y *= 0.99;
// Activate connected nodes with probability based on connection strength
for (const connIndex of node.connections) {
// Find the connection
const conn = this.connections.find(c =>
(c.from === i && c.to === connIndex) || (c.from === connIndex && c.to === i)
);
// Apply speed limits
node.speed.x = Math.max(-this.config.animationSpeed, Math.min(this.config.animationSpeed, node.speed.x));
node.speed.y = Math.max(-this.config.animationSpeed, Math.min(this.config.animationSpeed, node.speed.y));
if (conn) {
// Mark connection as recently activated
conn.lastActivated = now;
// Move node
node.x += node.speed.x;
node.y += node.speed.y;
// Boundary check with smooth bounce
if (node.x < 0 || node.x > width) {
node.speed.x *= -0.8; // Softer bounce
node.x = Math.max(0, Math.min(node.x, width));
// Create a flow along this connection
if (Math.random() < conn.strength * 0.8) {
this.flows.push({
connection: conn,
progress: 0,
direction: conn.from === i, // Flow from activated node
length: this.config.flowLength + Math.random() * 0.1,
intensity: 0.7 + Math.random() * 0.3 // Random intensity for variation
});
}
if (node.y < 0 || node.y > height) {
node.speed.y *= -0.8; // Softer bounce
node.y = Math.max(0, Math.min(node.y, height));
// Probability for connected node to activate
if (Math.random() < conn.strength * 0.5) {
this.nodes[connIndex].isActive = true;
this.nodes[connIndex].lastFired = now - Math.random() * 500; // Slight variation
}
// Update pulse phase
node.pulsePhase += this.config.pulseSpeed;
if (node.pulsePhase > Math.PI * 2) {
node.pulsePhase -= Math.PI * 2;
}
}
} else if (now - node.lastFired > 300) { // Deactivate after short period
node.isActive = false;
}
}
@@ -355,6 +442,11 @@ class NeuralNetworkBackground {
this.flows.splice(i, 1);
}
}
// Generate more flows for enhanced visibility
if (Math.random() < this.config.flowDensity * 2) {
this.createNewFlow();
}
}
// New method to create flow animations
@@ -416,14 +508,30 @@ class NeuralNetworkBackground {
const positions = new Float32Array(this.nodes.length * 2);
const sizes = new Float32Array(this.nodes.length);
const now = Date.now();
for (let i = 0; i < this.nodes.length; i++) {
const node = this.nodes[i];
positions[i * 2] = node.x;
positions[i * 2 + 1] = node.y;
// Size with subtle pulse effect
const pulse = Math.sin(node.pulsePhase) * 0.2 + 1;
sizes[i] = node.size * pulse * (node.connections.length > 3 ? 1.3 : 1);
// Enhanced pulse effect with additional boost for active nodes
let pulse = Math.sin(node.pulsePhase) * 0.4 + 1;
// Make active nodes pulse more intensely (neural firing effect)
if (node.isActive) {
const timeSinceFired = now - node.lastFired;
if (timeSinceFired < 300) {
// Quick expand then contract effect
const normalizedTime = timeSinceFired / 300;
const fireBoost = 1.5 * (1 - normalizedTime);
pulse += fireBoost;
}
}
// Nodes with more connections are larger (hub neurons)
const connectivityFactor = 1 + (node.connections.length / this.config.maxConnections) * 0.8;
sizes[i] = node.size * pulse * connectivityFactor;
}
// Bind position buffer
@@ -452,24 +560,45 @@ class NeuralNetworkBackground {
);
this.gl.enableVertexAttribArray(this.programInfo.attribLocations.pointSize);
// Set node color - more subtle
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
const nodeColor = this.hexToRgb(colorObj.nodeColor);
this.gl.uniform4f(
this.programInfo.uniformLocations.color,
nodeColor.r / 255,
nodeColor.g / 255,
nodeColor.b / 255,
0.7 // Lower opacity for subtlety
);
// Draw nodes
// Enable blending for all nodes
this.gl.enable(this.gl.BLEND);
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE); // Additive blending for glow
this.gl.drawArrays(this.gl.POINTS, 0, this.nodes.length);
// Draw each node individually with its own color
for (let i = 0; i < this.nodes.length; i++) {
const node = this.nodes[i];
// Set node color - more visible with active highlighting
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
const nodeColor = this.hexToRgb(colorObj.nodeColor);
const nodePulseColor = this.hexToRgb(colorObj.nodePulse);
// Use pulse color for active nodes
let r = nodeColor.r / 255;
let g = nodeColor.g / 255;
let b = nodeColor.b / 255;
// Active nodes get brighter color
if (node.isActive) {
r = (r + nodePulseColor.r / 255) / 2;
g = (g + nodePulseColor.g / 255) / 2;
b = (b + nodePulseColor.b / 255) / 2;
}
this.gl.uniform4f(
this.programInfo.uniformLocations.color,
r, g, b,
0.95 // Higher opacity for maximum visibility
);
// Draw each node individually for better control
this.gl.drawArrays(this.gl.POINTS, i, 1);
}
}
renderConnectionsWebGL() {
const now = Date.now();
// For each connection, draw a line
for (const connection of this.connections) {
const fromNode = this.nodes[connection.from];
@@ -497,15 +626,28 @@ class NeuralNetworkBackground {
// Disable point size attribute for lines
this.gl.disableVertexAttribArray(this.programInfo.attribLocations.pointSize);
// Set line color with connection opacity - darker, more subtle
// Set line color with connection opacity
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
const lineColor = this.hexToRgb(colorObj.connectionColor);
let lineColor = this.hexToRgb(colorObj.connectionColor);
// Highlight recently activated connections for neural pathway effect
let opacity = connection.opacity * 1.4; // Base increased visibility
if (now - connection.lastActivated < 800) {
// Make recently activated connections brighter
lineColor = this.hexToRgb(colorObj.flowColor);
// Fade out effect
const timeFactor = 1 - ((now - connection.lastActivated) / 800);
opacity = Math.max(opacity, timeFactor * 0.9);
}
this.gl.uniform4f(
this.programInfo.uniformLocations.color,
lineColor.r / 255,
lineColor.g / 255,
lineColor.b / 255,
connection.opacity * 0.8 // Reduced for subtlety
opacity
);
// Draw the line
@@ -585,7 +727,7 @@ class NeuralNetworkBackground {
1
);
// Flow color - subtle glow
// Flow color - much stronger glow
const colorObj = this.isDarkMode ? this.darkModeColors : this.lightModeColors;
const flowColor = this.hexToRgb(colorObj.flowColor);
this.gl.uniform4f(
@@ -593,13 +735,13 @@ class NeuralNetworkBackground {
flowColor.r / 255,
flowColor.g / 255,
flowColor.b / 255,
0.4 * fadeOpacity // Subtle flow opacity
0.9 * fadeOpacity * flow.intensity // Much stronger flow opacity with intensity variation
);
// Draw the flow line
this.gl.enable(this.gl.BLEND);
this.gl.blendFunc(this.gl.SRC_ALPHA, this.gl.ONE);
this.gl.lineWidth(1.5); // Slightly thicker for visibility
this.gl.lineWidth(2.5); // Even thicker for dramatic visibility
this.gl.drawArrays(this.gl.LINES, 0, 2);
}
}

Binary file not shown.