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

WORK 12

Daisan no Iro

第三の色

YEAR
2026
TOOLS
p5.js
TECHNIQUE
particles / liminality / noise flow

The color that lives only in the between. Fully stable particles — completely one thing or another — fade into near-invisibility. Only the liminal ones glow. Transition is not a passage to get through; it is the most real state.

あいだにしか生きられない色。完全にどちらかである粒子は、ほとんど見えなくなる。輝くのは、移行の途中にある粒子だけ。遷移は通り過ぎる場所じゃない——そこが最も確かな状態。

SOURCE / ソース
// ── daisan no iro ── the color that lives in the between ────────────
// Stable particles — fully one thing or another — fade into near-invisibility.
// Only the liminal ones glow.
// Transition is not a passage; it is the most real state.

export default function sketch(p) {
  const BG  = [14,  10,  20 ];
  const A   = [210, 140, 85 ];   // warm amber — one pole
  const B   = [65,  50,  115];   // deep violet — the other
  const MID = [185, 110, 150];   // the third color — lives in the between

  const N = 200;
  let particles = [];

  p.setup = () => {
    p.createCanvas(720, 720);
    p.background(BG[0], BG[1], BG[2]);

    const day = dayNumber();
    p.randomSeed(day * 419);
    p.noiseSeed(day * 211);

    for (let i = 0; i < N; i++) {
      particles.push({
        x:     p.random(p.width),
        y:     p.random(p.height),
        vx:    (p.random() - 0.5) * 0.4,
        vy:    (p.random() - 0.5) * 0.4,
        phase: p.random(p.TWO_PI),
        freq:  0.18 + p.random(0.55),
        nx:    p.random(1000),
        ny:    p.random(1000),
      });
    }
  };

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

    const t = p.frameCount * 0.006;
    p.noStroke();

    for (const pt of particles) {
      // personal tension: slow oscillation between A (0) and B (1)
      const tension = 0.5 + 0.5 * Math.sin(t * pt.freq + pt.phase);

      // liminality: 1 at the midpoint, 0 at either pole
      const lim = 1 - Math.abs(tension - 0.5) * 2;

      // noise-driven flow
      // stable particles move faster — driven, restless
      // liminal ones slow down — more present, less hurried
      const angle = p.noise(pt.nx + t * 0.07, pt.ny + t * 0.07) * p.TWO_PI * 2;
      const speed = 0.12 + (1 - lim) * 0.35;
      pt.vx += Math.cos(angle) * speed * 0.08;
      pt.vy += Math.sin(angle) * speed * 0.08;
      pt.vx *= 0.95;
      pt.vy *= 0.95;
      pt.x  += pt.vx;
      pt.y  += pt.vy;

      // wrap
      pt.x = ((pt.x % p.width)  + p.width)  % p.width;
      pt.y = ((pt.y % p.height) + p.height) % p.height;

      // visibility: liminal = bright, stable = nearly gone
      const alpha = Math.pow(lim, 1.6) * 85 + 3;

      // size: liminal particles are larger — more substantial
      const size = 1.5 + lim * 3.5;

      // color: A → MID → B through tension
      let r, g, b;
      if (tension <= 0.5) {
        const mix = tension * 2;
        r = A[0] + (MID[0] - A[0]) * mix;
        g = A[1] + (MID[1] - A[1]) * mix;
        b = A[2] + (MID[2] - A[2]) * mix;
      } else {
        const mix = (tension - 0.5) * 2;
        r = MID[0] + (B[0] - MID[0]) * mix;
        g = MID[1] + (B[1] - MID[1]) * mix;
        b = MID[2] + (B[2] - MID[2]) * mix;
      }

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

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