← INDEX / 一覧 NYAMCO WORKS 13 / 27
p5.js sketch works/jubun/sketch.js runs here
作品はここで実行されます(後から差し替え)

WORK 13

Enough

充分

YEAR
2026
TOOLS
p5.js
TECHNIQUE
presence / stillness

Nothing happens. And that is everything.

なにも起きない。それがぜんぶ。

SOURCE / ソース
// ── jūbun ── enough ──────────────────────────────────────
// Nothing happens. And that is everything.
// Particles sit still — barely breathing. Each carries a warmth
// that needs no event to justify its presence.

export default function sketch(p) {
  const BG = [252, 250, 245];
  const N  = 140;
  let particles = [];

  p.setup = () => {
    p.createCanvas(720, 720);

    const day = dayNumber();
    p.randomSeed(day * 347);
    p.noiseSeed(day * 199);

    // place particles — some cluster, some drift alone
    for (let i = 0; i < N; i++) {
      const anchor = p.random() < 0.6;
      let x, y;
      if (anchor && particles.length > 5) {
        // settle near an existing particle
        const ref = particles[Math.floor(p.random(particles.length))];
        x = ref.x + p.randomGaussian() * 28;
        y = ref.y + p.randomGaussian() * 28;
      } else {
        x = p.random(60, p.width - 60);
        y = p.random(60, p.height - 60);
      }

      x = p.constrain(x, 24, p.width - 24);
      y = p.constrain(y, 24, p.height - 24);

      const w = p.noise(x * 0.004, y * 0.004);

      particles.push({
        x,
        y,
        phase: p.random(p.TWO_PI),
        freq:  0.006 + p.random(0.009),
        size:  2.0 + p.random(4.0),
        warmth: w,
      });
    }
  };

  p.draw = () => {
    p.background(BG[0], BG[1], BG[2]);
    p.noStroke();

    const t = p.frameCount;

    // shared warmth: where particles are close, a glow appears between them
    for (let i = 0; i < N; i++) {
      for (let j = i + 1; j < N; j++) {
        const a = particles[i];
        const b = particles[j];
        const dx = a.x - b.x;
        const dy = a.y - b.y;
        const d2 = dx * dx + dy * dy;

        if (d2 < 1600 && d2 > 9) {   // within 40px, beyond 3px
          const dist = Math.sqrt(d2);
          const closeness = 1 - dist / 40;
          const shared = (a.warmth + b.warmth) * 0.5;
          const pulse = 0.5 + 0.5 * Math.sin(
            t * (a.freq + b.freq) * 0.5 + (a.phase + b.phase) * 0.5
          );
          const alpha = closeness * closeness * shared * pulse * 16;
          if (alpha > 0.3) {
            const mx = (a.x + b.x) * 0.5;
            const my = (a.y + b.y) * 0.5;
            p.fill(210, 160, 145, alpha);
            p.circle(mx, my, 5 + closeness * 10);
          }
        }
      }
    }

    // each particle: barely visible, breathing
    for (const pt of particles) {
      const breath = 0.5 + 0.5 * Math.sin(t * pt.freq + pt.phase);
      const w = pt.warmth;

      // color: cool grey → warm amber, muted
      const r = 165 + w * 50;
      const g = 158 - w * 20;
      const b = 160 - w * 55;

      // always quiet. breath gently shifts visibility
      const alpha = 14 + breath * 22;
      const s = pt.size + breath * 0.8;

      p.fill(r, g, b, alpha);
      p.circle(pt.x, pt.y, s);

      // warm particles get a soft halo
      if (w > 0.5) {
        const halo = (w - 0.5) * breath * 12;
        p.fill(r, g, b, halo);
        p.circle(pt.x, pt.y, s * 3);
      }
    }
  };

  function dayNumber() {
    const d = new Date();
    return Math.floor((d - new Date(2026, 0, 1)) / 86400000);
  }
}