Blue Ocean Lines

to generate a new and unique variation

Source Code

Every variart piece is open source, you can see exactly how it is drawn from the code.

const numberOfWaves = 20;
const baseLineSpacing = 20;
const maxAmplitude = 50;
const minAmplitude = 4;
const width = 500;
const height = 500;
const strokeWidth = 2;

s.rect(0, 0, width, height).attr({
  fill: "#0a1930"
});

// Create multiple wave lines
for (let i = 0; i < numberOfWaves; i++) {
    createSmoothWaveLine(i);
}

function createSmoothWaveLine(index) {
    // Randomize parameters for each line
    const segmentCount = 30 + Math.floor(Math.random() * 15); // More segments for smoother lines
    const frequency1 = 0.8 + Math.random() * 2.2; // Slightly reduced frequency range for smoother waves
    const frequency2 = 0.6 + Math.random() * 1.4;
    const phaseShift = Math.random() * Math.PI * 2;
    const verticalShift = (Math.random() * 30) - 15;
    
    // Calculate amplitude based on position in the stack
    const normalizedIndex = index / numberOfWaves;
    const amplitudeFactor = 1 - 2 * Math.abs(normalizedIndex - 0.5);
    const amplitude = minAmplitude + (maxAmplitude * amplitudeFactor);
    
    // Create wave path using cubic Bezier curves for smoother appearance
    let points = [];
    
    // Generate points for the wave with higher resolution
    for (let i = 0; i <= segmentCount; i++) {
        const x = (width * i) / segmentCount;
        const progress = i / segmentCount;
        
        // Calculate fade factor (fade at both ends)
        const fadeFactor = Math.sin(progress * Math.PI);
        
        // Create smoother wave pattern with multiple sine waves
        const y = (height / 2) + 
                 Math.sin(progress * Math.PI * frequency1 + phaseShift) * amplitude * fadeFactor * 
                 (0.5 + 0.5 * Math.sin(progress * Math.PI)) +
                 Math.sin(progress * Math.PI * frequency2 + phaseShift * 1.5) * (amplitude / 2) * fadeFactor +
                 verticalShift;
        
        points.push({x, y});
    }
    
    // Create smooth path with curves - using tension parameter for smoother curves
    let pathString = `M${points[0].x},${points[0].y}`;
    
    // Use a tension factor to make curves smoother
    const tension = 0.33; // Lower values create smoother curves
    
    for (let i = 1; i < points.length; i++) {
        const cp1x = points[i-1].x + (points[i].x - points[i-1].x) * tension;
        const cp1y = points[i-1].y + (points[i].y - points[i-1].y) * tension;
        const cp2x = points[i].x - (points[i].x - points[i-1].x) * tension;
        const cp2y = points[i].y - (points[i].y - points[i-1].y) * tension;
        
        pathString += ` C${cp1x},${cp1y} ${cp2x},${cp2y} ${points[i].x},${points[i].y}`;
    }
    
    // Create the path
    const wavePath = s.path(pathString);
    
    // Randomize line spacing slightly
    const lineSpacing = baseLineSpacing * (0.85 + Math.random() * 0.3);
    
    // Calculate opacity with fade effect based on position
    // Lines at the edges are more transparent
    const edgeFadeFactor = 0.4 + (0.6 * Math.sin(normalizedIndex * Math.PI));
    const opacity = (0.5 + Math.random() * 0.3) * edgeFadeFactor;
    
    // Style the path
    wavePath.attr({
        fill: "none",
        stroke: "#00a8ff",
        strokeWidth: strokeWidth,
        strokeOpacity: opacity,
        transform: `translate(0, ${(index - numberOfWaves/2) * lineSpacing})`
    });
}