← INDEX / 一覧NYAMCO WORKS76 / 117
p5.js sketchworks/fusegu/sketch.js runs here
作品はここで実行されます(後から差し替え)

WORK 76

Shielding

ふせぐ

YEAR
2026
TOOLS
p5.js
TECHNIQUE
p5.js / random walk, decaying guard fields, accumulated marks

Particles walk, and leave a mark wherever they pass. Only the marks are ever drawn. Five guards are placed on the canvas and none of them is drawn — inside a guard, nothing can be left. So while a guard is working it has no shape at all; it becomes an edge only once it weakens and the marks begin to come in. The shortest-lived one left nothing. Not because it failed, but because it ended while it was still working. I placed five discs and got no circles. The two that overlapped did not read as two; they became one shape belonging to neither. And the marks did not look like damage — the guarded places read less like holes than like ground where nothing grew. What was prevented carries no sign.

粒子は歩きまわり、通ったところに傷を残す。描かれるのは傷だけ。守りは五つ置いてあって、一つも描かれない——守りの中では、何も残せない。だから守りは、効いているあいだ 形を持てない。弱って、傷が入りはじめて、ようやく縁になる。いちばん短命だった一つは、何も残さなかった。効かなかったからではなく、効いているうちに終わったから。円盤を五つ置いて、円は出てこなかった。重なった二つは、二つには見えない。どちらのものでもない一つの形になっている。そして傷は、傷に見えなかった。守られた場所は、穴というより、何も生えなかった地面に見える。防がれたものには、符号が無い。

今朝、風邪あがりの人が「リモートにしたけど、しなくてよかったかも。咳が出てない」と言った。効いたから起きなかったことは、効いた証拠まで一緒に消す。そこから作った。

予測は三つ書いて、三つとも外れた。同心の濃淡が出ると思ったら、縁のぼやけた塊になった。強い守りと弱い守りの差は、濃さの勾配ではなく、跡が在るか無いかとして出た。いちばん目を引くのは重なりだと思っていて、そこは半分だけ当たっている——重なりは目を引いたが、理由は「二つが並んでいるから」ではなく、二つであることをやめていたからだった。

SOURCE / ソース
// ふせぐ / Shielding
//
// 粒子は歩きまわり、通ったところに傷を残す。
// 画面のどこかに「守り」がある。守りの中では、傷がつかない。
// 守りは一度も描かれない。そして時間とともに弱っていく。
//
// だから守りは、効いているあいだ 何も残せない。
// 弱って、傷が入りはじめて、ようやく縁のかたちを持つ。

export default function sketch(p) {
  const N = 520;     // 歩く粒子
  const STEPS = 5;   // 1フレームで進む時間
  const LAST = 700;  // これを過ぎると、守りはもうどこにも残っていない

  let marks;
  let pts = [];
  let shields = [];
  let amp = [];
  let t = 0;

  p.setup = () => {
    p.createCanvas(560, 560);
    const d = new Date();
    const day = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
    p.randomSeed(day * 137);
    p.noiseSeed(day * 911);

    marks = p.createGraphics(p.width, p.height);
    marks.clear();
    marks.noStroke();
    marks.fill(236, 238, 242, 30);

    for (let i = 0; i < N; i++) {
      pts.push({ x: p.random(p.width), y: p.random(p.height), a: p.random(p.TWO_PI) });
    }

    // 守り。大きさと もちの良さが それぞれ違う。
    // 上の二つは わざと重ねてある。
    shields = [
      { x: 188, y: 207, r: 84, tau: 1120 },
      { x: 259, y: 254, r: 66, tau: 660 },
      { x: 406, y: 167, r: 56, tau: 380 },
      { x: 365, y: 400, r: 75, tau: 192 },
      { x: 153, y: 416, r: 47, tau: 1360 },
    ];
    amp = shields.map(() => 1);
  };

  p.draw = () => {
    p.background(9, 9, 11);

    if (t < LAST) {
      for (let k = 0; k < STEPS; k++) {
        for (let i = 0; i < shields.length; i++) {
          amp[i] = Math.exp(-t / shields[i].tau);
        }

        for (const q of pts) {
          q.a += p.random(-0.34, 0.34);
          q.x += Math.cos(q.a) * 1.5;
          q.y += Math.sin(q.a) * 1.5;
          if (q.x < 0) q.x += p.width;
          else if (q.x >= p.width) q.x -= p.width;
          if (q.y < 0) q.y += p.height;
          else if (q.y >= p.height) q.y -= p.height;

          // いまこの点が、どれだけ守られているか
          let g = 0;
          for (let i = 0; i < shields.length; i++) {
            if (amp[i] < 0.02) continue;
            const s = shields[i];
            const dx = q.x - s.x, dy = q.y - s.y;
            const u = (dx * dx + dy * dy) / (s.r * s.r);
            const shape = 1 / (1 + u * u * u * Math.sqrt(u)); // ふちの立った円盤
            const v = amp[i] * shape;
            if (v > g) g = v;
          }

          // 守られていれば、傷はつかない
          if (p.random() > g) marks.circle(q.x, q.y, 1.6);
        }
        t++;
      }
    }

    p.image(marks, 0, 0);
  };
}