DEV Community

Cover image for 用 p5.js 做出會回應滑鼠的日式粒子背景,讓你的作品頁面更有互動感
張旭豐
張旭豐

Posted on

用 p5.js 做出會回應滑鼠的日式粒子背景,讓你的作品頁面更有互動感

讓你的作品集「活」起來:日式互動粒子背景拆解

很多設計系同學在做作品集網頁時,最頭痛的就是「首頁太死板」。想要一點互動感,但看到程式碼就頭大。

其實,要做出像 TeamLab 那種「有靈魂」的視覺效果,不需要成為工程師,你只需要掌握「粒子系統」這個簡單的邏輯。

今天我想分享如何用 p5.js 做出一個具有日式美學(低飽和、流動感、留白)的互動背景。

🎨 作品拆解:視覺語言的定義

在動手寫 code 之前,我們先把視覺拆解成設計語言。這篇文章追求的不是「科技感」,而是「禪意」。

  • 色彩 (Color)
    • 背景:使用 #F5F5F0(淡淡的和紙白),避免純白導致的視覺疲勞。
    • 粒子:主色用 #2C2C2C(墨黑),點綴色用 #E57373(淡櫻紅)。
  • 動態 (Motion)
    • 粒子不應該直線移動,而應該像在水中漂浮。我們使用 noise() 函數來達成這種「有機」的流動感。
  • 互動 (Interaction)
    • 當滑鼠靠近時,粒子不應該直接消失,而是像被溫柔地「推開」。

🛠️ 跟著做:三個階段完成互動視覺

你可以直接將下方的【完整版程式碼】貼進 p5.js Web Editor 立即看到結果,但建議分三個階段來理解它是如何被「疊加」出來的。

階段一:在畫布上種下「粒子」

想像每顆粒子就像一片浮在水面的紙屑。它需要記住自己現在在哪裡(位置),以及接下來要往哪裡飄(速度)。

在程式碼中,我們用 class Particle 來定義這片紙屑的「屬性」。

視覺結果:你會在畫布上看到一群隨機分佈的小圓點,像靜止的星空。

階段二:賦予粒子「生命」(流動感)

要讓粒子像在水中漂浮而非機械抖動,我們使用 noise()。它會產生一種平滑的隨機值,讓粒子在移動時有自然的弧度。

視覺結果:圓點開始輕微地、有機地漂動,畫面產生了一種「呼吸感」。

階段三:建立與使用者的「連結」(滑鼠互動)

最神奇的地方在於:我們計算粒子與滑鼠的距離。如果滑鼠太靠近,就給粒子一個「逃離」的力,把它們溫柔地推開。

視覺結果:當你的滑鼠在螢幕上移動時,粒子會像受驚的魚群一樣自然散開,離開後會繼續順著流場漂動,保持畫面自然的靈動感。


💻 完整實作程式碼 (可以直接複製使用)

let particles = [];

function setup() {
  createCanvas(windowWidth, windowHeight);
  for (let i = 0; i < 100; i++) {
    particles.push(new Particle());
  }
}

function draw() {
  background('#F5F5F0'); // 和紙白
  for (let p of particles) {
    p.update();
    p.display();
  }
}

function windowResized() {
  resizeCanvas(windowWidth, windowHeight);
}

class Particle {
  constructor() {
    this.pos = createVector(random(width), random(height));
    this.vel = createVector(0, 0);
    this.acc = createVector(0, 0);
    this.maxspeed = 2;
    this.color = random() > 0.9 ? '#E57373' : '#2C2C2C';
  }

  update() {
    // 1. 有機流動感 (Noise)
    let angle = noise(this.pos.x * 0.01, this.pos.y * 0.01, frameCount * 0.01) * TWO_PI * 2;
    let noiseForce = p5.Vector.fromAngle(angle).mult(0.1);
    this.acc.add(noiseForce);

    // 2. 滑鼠互動
    let mouse = createVector(mouseX, mouseY);
    let dir = p5.Vector.sub(this.pos, mouse);
    let d = dir.mag();
    if (d < 100) {
      dir.setMag(1);
      dir.mult(map(d, 0, 100, 1, 0)); 
      this.acc.add(dir);
    }

    this.vel.add(this.acc);
    this.vel.limit(this.maxspeed);
    this.pos.add(this.vel);
    this.acc.mult(0);

    // 3. 邊界處理:飄出畫面後從另一側回來 (Wrap)
    if (this.pos.x < 0) this.pos.x = width;
    if (this.pos.x > width) this.pos.x = 0;
    if (this.pos.y < 0) this.pos.y = height;
    if (this.pos.y > height) this.pos.y = 0;
  }

  display() {
    fill(this.color);
    noStroke();
    ellipse(this.pos.x, this.pos.y, 4, 4);
  }
}
Enter fullscreen mode Exit fullscreen mode

🗺️ 作品集應用:這個模組還能怎麼用?

你現在已經做出一個可以放進作品集首頁的互動背景了。這個 Canvas 可以直接放在 Hero Section 的最底層作為背景,增加頁面的層次感。接下來,你可以嘗試調整這三個地方,讓它更符合你的風格:

  1. 改變粒子形狀:把 ellipse 改成 rectline,視覺感會從「有機」變成「建築感」。
  2. 調整互動距離:將 if (d < 100) 改成 50(更內斂)或 300(更激進),改變作品的情緒。
  3. 結合滾動事件:嘗試讓粒子在頁面滾動時改變顏色或速度,創造更深層的敘事感。

互動設計的核心不是程式碼,而是你想要傳達的「感覺」。

Top comments (0)