File size: 7,699 Bytes
6193995
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
(function () {
  const canvas = document.getElementById('dm-shader-bg');
  if (!canvas) return;

  const gl = canvas.getContext('webgl');
  if (!gl) {
    console.warn('DataMind: WebGL not supported, shader background skipped.');
    return;
  }

  // ── Vertex Shader ─────────────────────────────────────────────────────────
  const vsSource = `
    attribute vec4 aVertexPosition;
    void main() {
      gl_Position = aVertexPosition;
    }
  `;

  // ── Fragment Shader β€” DataMind colour palette ──────────────────────────────
  const fsSource = `
    precision highp float;
    uniform vec2  iResolution;
    uniform float iTime;

    const float overallSpeed      = 0.15;
    const float gridSmoothWidth   = 0.015;
    const float axisWidth         = 0.05;
    const float majorLineWidth    = 0.025;
    const float minorLineWidth    = 0.0125;
    const float majorLineFreq     = 5.0;
    const float minorLineFreq     = 1.0;
    const float scale             = 5.0;

    /* ── Cyan accent #00d4ff ── */
    const vec4  lineColor         = vec4(0.0, 0.831, 1.0, 1.0);

    const float minLineWidth      = 0.01;
    const float maxLineWidth      = 0.18;
    const float lineSpeed         = 1.0  * overallSpeed;
    const float lineAmplitude     = 1.0;
    const float lineFrequency     = 0.2;
    const float warpSpeed         = 0.2  * overallSpeed;
    const float warpFrequency     = 0.5;
    const float warpAmplitude     = 1.0;
    const float offsetFrequency   = 0.5;
    const float offsetSpeed       = 1.33 * overallSpeed;
    const float minOffsetSpread   = 0.6;
    const float maxOffsetSpread   = 2.0;
    const int   linesPerGroup     = 16;

    #define drawCircle(pos, radius, coord) \
      smoothstep(radius + gridSmoothWidth, radius, length(coord - (pos)))
    #define drawSmoothLine(pos, halfWidth, t) \
      smoothstep(halfWidth, 0.0, abs(pos - (t)))
    #define drawCrispLine(pos, halfWidth, t) \
      smoothstep(halfWidth + gridSmoothWidth, halfWidth, abs(pos - (t)))
    #define drawPeriodicLine(freq, width, t) \
      drawCrispLine(freq / 2.0, width, abs(mod(t, freq) - (freq) / 2.0))

    float random(float t) {
      return (cos(t) + cos(t * 1.3 + 1.3) + cos(t * 1.4 + 1.4)) / 3.0;
    }

    float getPlasmaY(float x, float hFade, float offset) {
      return random(x * lineFrequency + iTime * lineSpeed) * hFade * lineAmplitude + offset;
    }

    void main() {
      vec2 fragCoord = gl_FragCoord.xy;
      vec2 uv    = fragCoord / iResolution.xy;
      vec2 space = (fragCoord - iResolution.xy * 0.5) / iResolution.x * 2.0 * scale;

      float hFade = 1.0 - (cos(uv.x * 6.28318) * 0.5 + 0.5);
      float vFade = 1.0 - (cos(uv.y * 6.28318) * 0.5 + 0.5);

      /* subtle warp */
      space.y += random(space.x * warpFrequency + iTime * warpSpeed) * warpAmplitude * (0.5 + hFade);
      space.x += random(space.y * warpFrequency + iTime * warpSpeed + 2.0) * warpAmplitude * hFade;

      vec4 lines = vec4(0.0);

      /* ── Background gradient: #161a24 β†’ #1a1a2e ── */
      vec4 bgColor1 = vec4(0.086, 0.102, 0.141, 1.0);
      vec4 bgColor2 = vec4(0.102, 0.102, 0.180, 1.0);

      for (int l = 0; l < linesPerGroup; l++) {
        float nli          = float(l) / float(linesPerGroup);
        float offsetTime   = iTime * offsetSpeed;
        float offsetPos    = float(l) + space.x * offsetFrequency;
        float rand         = random(offsetPos + offsetTime) * 0.5 + 0.5;
        float halfWidth    = mix(minLineWidth, maxLineWidth, rand * hFade) * 0.5;
        float offset       = random(offsetPos + offsetTime * (1.0 + nli))
                             * mix(minOffsetSpread, maxOffsetSpread, hFade);
        float linePos      = getPlasmaY(space.x, hFade, offset);
        float line         = drawSmoothLine(linePos, halfWidth, space.y) * 0.5
                           + drawCrispLine(linePos, halfWidth * 0.15, space.y);

        float circleX      = mod(float(l) + iTime * lineSpeed, 25.0) - 12.0;
        vec2  circlePos    = vec2(circleX, getPlasmaY(circleX, hFade, offset));
        float circle       = drawCircle(circlePos, 0.01, space) * 4.0;

        lines += (line + circle) * lineColor * rand;
      }

      vec4 fragColor  = mix(bgColor1, bgColor2, uv.x);
      fragColor      *= vFade;
      fragColor.a     = 1.0;
      fragColor      += lines;

      gl_FragColor = fragColor;
    }
  `;

  // ── Compile helpers ────────────────────────────────────────────────────────
  function compileShader(gl, type, source) {
    const shader = gl.createShader(type);
    gl.shaderSource(shader, source);
    gl.compileShader(shader);
    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
      console.error('Shader error:', gl.getShaderInfoLog(shader));
      gl.deleteShader(shader);
      return null;
    }
    return shader;
  }

  function createProgram(gl, vs, fs) {
    const prog = gl.createProgram();
    gl.attachShader(prog, vs);
    gl.attachShader(prog, fs);
    gl.linkProgram(prog);
    if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) {
      console.error('Program link error:', gl.getProgramInfoLog(prog));
      return null;
    }
    return prog;
  }

  // ── Build program ──────────────────────────────────────────────────────────
  const vs      = compileShader(gl, gl.VERTEX_SHADER,   vsSource);
  const fs      = compileShader(gl, gl.FRAGMENT_SHADER, fsSource);
  const program = createProgram(gl, vs, fs);
  if (!program) return;

  const posBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
  gl.bufferData(
    gl.ARRAY_BUFFER,
    new Float32Array([-1, -1,  1, -1,  -1, 1,  1, 1]),
    gl.STATIC_DRAW
  );

  const aPos       = gl.getAttribLocation(program,  'aVertexPosition');
  const uRes       = gl.getUniformLocation(program, 'iResolution');
  const uTime      = gl.getUniformLocation(program, 'iTime');

  // ── Resize ─────────────────────────────────────────────────────────────────
  function resize() {
    const parent = canvas.parentElement;
    canvas.width  = parent ? parent.offsetWidth  : window.innerWidth;
    canvas.height = parent ? parent.offsetHeight : window.innerHeight;
    gl.viewport(0, 0, canvas.width, canvas.height);
  }
  window.addEventListener('resize', resize);
  resize();

  // ── Render loop ────────────────────────────────────────────────────────────
  const startTime = Date.now();

  function render() {
    // Stop rendering if canvas is no longer visible (dashboard loaded)
    if (!canvas.isConnected || canvas.offsetParent === null) return;

    const t = (Date.now() - startTime) / 1000;

    gl.clearColor(0, 0, 0, 1);
    gl.clear(gl.COLOR_BUFFER_BIT);

    gl.useProgram(program);
    gl.uniform2f(uRes, canvas.width, canvas.height);
    gl.uniform1f(uTime, t);

    gl.bindBuffer(gl.ARRAY_BUFFER, posBuffer);
    gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(aPos);

    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    requestAnimationFrame(render);
  }

  requestAnimationFrame(render);
})();