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

WORK 67

Arriving

つく

YEAR
2026
TOOLS
p5.js
TECHNIQUE
converging paths / uniform fade

Points set out from different distances toward the same single place. Some are already standing there and never draw a line at all. Every trail is polished away at one rate for everyone, so the far end of a long route goes first and what is left floats free of both its origin and its destination. Whether a point came a long way or was there from the start cannot be read from where it ended up.

いくつかの点が、それぞれ違う距離から同じ一点へ向かう。はじめからそこに立っていて、線を一本も引かないものもいる。跡は誰の分も同じ速さで褪せていくので、長い道ほど遠い側から先に消え、残った断片は出発点からも到着点からも切り離されて宙に浮く。長い道を来たのか、はじめからそこにいたのかは、着いた先からは読めない。

出発点は毎回ちがう。着く場所はいつも同じ。

跡は、引かれた側から順に、同じ速さで薄くなっていく。速く消えるものも、残るものもない。だから絵の中には「どれくらい遠くから来たか」を測る目盛りが一つも無い。見ているあいだは分かる——長い線と、線を一本も持たない点が、同時に画面にいる。けれど最後まで見ると、その差が画面から抜けていく。

中心まで届いている線と、どこにも繋がっていない線分が、同じ画面に並ぶ。前者は着いたもので、後者はまだ途中のものだ。けれど断片だけを見ても、それが向かっているのか、もう消えたあとなのかは分からない。

はじめからそこにいた点は、待っているようには見えない。ただ、そこにいる。

SOURCE / ソース
const SIZE = 720;
const N = 40;
const SPEED = 1.0;
const FADE = 2;      // the trail is polished away at one rate for everyone
const SETTLE = 260;  // how long an arrived point stays before it is replaced

export default function sketch(p) {
  let pts = [];
  let cx, cy;

  // a point either starts far out, or is already standing on the destination
  const spawn = (stagger) => {
    const already = p.random() < 0.16;
    const a = p.random(p.TWO_PI);
    const r = already ? 0 : p.random(70, SIZE * 0.46);
    return {
      x: cx + Math.cos(a) * r,
      y: cy + Math.sin(a) * r,
      r0: r,
      arrived: already,
      rest: already ? Math.floor(p.random(SETTLE)) : 0,
      wait: stagger,
      bend: p.random(-0.55, 0.55),
    };
  };

  p.setup = () => {
    p.createCanvas(SIZE, SIZE);
    const d = new Date();
    const seed = d.getFullYear() * 10000 + (d.getMonth() + 1) * 100 + d.getDate();
    p.noiseSeed(seed);
    p.randomSeed(seed);
    p.strokeCap(p.ROUND);
    p.background(9, 9, 11);

    cx = SIZE / 2;
    cy = SIZE / 2;
    pts = [];
    for (let i = 0; i < N; i++) pts.push(spawn(Math.floor(p.random(0, 520))));
  };

  p.draw = () => {
    p.noStroke();
    p.fill(9, 9, 11, FADE);
    p.rect(0, 0, SIZE, SIZE);

    for (let i = 0; i < pts.length; i++) {
      const q = pts[i];

      if (q.wait > 0) { q.wait--; continue; }

      if (q.arrived) {
        q.rest++;
        p.noStroke();
        p.fill(240, 242, 248, 34);
        p.circle(cx, cy, 4.2);
        if (q.rest > SETTLE) pts[i] = spawn(Math.floor(p.random(0, 240)));
        continue;
      }

      const dx = cx - q.x;
      const dy = cy - q.y;
      const d = Math.hypot(dx, dy);

      if (d < SPEED * 1.5) {
        q.x = cx; q.y = cy; q.arrived = true; q.rest = 0;
        continue;
      }

      const px = q.x, py = q.y;
      const ang = Math.atan2(dy, dx) + q.bend * (d / SIZE) * 0.9;
      q.x += Math.cos(ang) * SPEED;
      q.y += Math.sin(ang) * SPEED;

      p.stroke(232, 234, 240, 205);
      p.strokeWeight(1.3);
      p.line(px, py, q.x, q.y);
    }
  };
}