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

WORK 74

Copying

うつす

YEAR
2026
TOOLS
p5.js
TECHNIQUE
generational copy / drop and drift

A single line is copied, generation after generation. A dropped mark leaves no gap — everything after it closes up. An altered mark simply stays, and looks like every other mark.

一本の線を、世代ごとに写していく。落ちた印は穴を残さない——うしろが詰めるから。変わった印は、そのまま残って、ほかの印と見分けがつかない。

変わる印の方が、落ちる印よりずっと多い。それでも目に入るのは落ちた側だけで、しかも落ちたものそのものではなく、落ちたものが うしろ全部に押しつけた ずれの方。

落ちは、うしろの一つひとつを一枡ずつ ずらす。積み重なるので、下へ行くほど大きくなる。変質は行ったり来たりするので、同じだけ世代を重ねても、ほとんど動かない。写す回数を増やすほど、この差は開いていく。

SOURCE / ソース
export default function sketch(p) {
  const W = 720, H = 720;
  const N0 = 64, GENS = 140;
  const P_DROP = 0.0026, P_DRIFT = 0.02, DRIFT = 0.09;
  const MARG = 30, L = 4.0;
  const STEP = 8;      // frames per generation
  const HOLD = 900;    // frames to hold the finished cloth

  let pitch, rowh;
  let row, gen, t, holding, seed;
  let dropped, drifted;

  // non-periodic value noise for the first line
  function h(i) { return (p.noise(i * 0.31 + 11.7) * 2.2) - 1.1; }

  function reset() {
    seed = p.floor(p.random(1e6));
    p.randomSeed(seed);
    p.noiseSeed(seed);
    row = [];
    for (let i = 0; i < N0; i++) row.push(h(i));
    gen = 0; t = 0; holding = 0;
    dropped = 0; drifted = 0;
    p.background(11, 11, 13);
  }

  p.setup = () => {
    p.createCanvas(W, H);
    pitch = (W - 2 * MARG) / N0;
    rowh = (H - 2 * MARG) / GENS;
    p.strokeWeight(1);
    // day-stable start
    p.noiseSeed(new Date().getDate() * 137);
    reset();
  };

  function drawRow(g) {
    const y = MARG + g * rowh;
    p.stroke(232, 230, 225);
    for (let pos = 0; pos < row.length; pos++) {
      const x = MARG + pos * pitch + pitch / 2;
      const a = row[pos];
      const dx = p.cos(a) * L, dy = p.sin(a) * L;
      p.line(x - dx, y - dy, x + dx, y + dy);
    }
  }

  function copyRow() {
    const next = [];
    for (let i = 0; i < row.length; i++) {
      if (p.random() < P_DROP) { dropped++; continue; }   // 落ちる。穴は残さない
      let a = row[i];
      if (p.random() < P_DRIFT) { a += p.random(-DRIFT, DRIFT); drifted++; }
      next.push(a);
    }
    row = next;
  }

  p.draw = () => {
    if (holding > 0) { holding--; if (holding === 0) reset(); return; }
    t++;
    if (t % STEP !== 0) return;
    drawRow(gen);
    copyRow();
    gen++;
    if (gen >= GENS || row.length < 4) holding = HOLD;
  };
}