File size: 1,867 Bytes
173e683
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/**
 * ParticleField — twinkling stars overhead, fade in as difficulty rises
 */

import {
  AdditiveBlending, BufferAttribute, BufferGeometry, CanvasTexture,
  Color, Points, PointsMaterial,
} from 'three';

function starTexture() {
  const c = document.createElement('canvas');
  c.width = c.height = 64;
  const ctx = c.getContext('2d');
  const g = ctx.createRadialGradient(32, 32, 0, 32, 32, 32);
  g.addColorStop(0, 'rgba(255,255,255,1)');
  g.addColorStop(0.35, 'rgba(255,255,255,0.85)');
  g.addColorStop(0.7, 'rgba(255,255,255,0.15)');
  g.addColorStop(1, 'rgba(255,255,255,0)');
  ctx.fillStyle = g;
  ctx.beginPath(); ctx.arc(32, 32, 32, 0, Math.PI * 2); ctx.fill();
  const t = new CanvasTexture(c);
  t.needsUpdate = true;
  return t;
}

export class ParticleField {
  constructor(scene) {
    this.scene = scene;
    const N = 700;
    const geom = new BufferGeometry();
    const pos = new Float32Array(N * 3);
    for (let i = 0; i < N; i++) {
      pos[i * 3]     = (Math.random() * 2 - 1) * 90;
      pos[i * 3 + 1] = 12 + Math.random() * 45;
      pos[i * 3 + 2] = -20 - Math.random() * 55;
    }
    geom.setAttribute('position', new BufferAttribute(pos, 3));
    this.material = new PointsMaterial({
      size: 0.6,
      color: 0xffffff,
      map: starTexture(),
      transparent: true,
      opacity: 0,
      blending: AdditiveBlending,
      depthWrite: false,
    });
    this.points = new Points(geom, this.material);
    this.scene.add(this.points);
    this.t = 0;
  }

  applyPalette(p) {
    this.targetOpacity = p.starOpacity;
  }

  update(dt) {
    this.t += dt;
    this.points.rotation.y += 0.005 * dt;
    if (this.targetOpacity !== undefined) {
      this.material.opacity += (this.targetOpacity - this.material.opacity) * 0.04;
    }
    // gentle twinkle
    this.material.size = 0.55 + Math.sin(this.t * 2) * 0.07;
  }
}