Uncreative Coding / アンクリエイティブ・コーディング

久保田 晃弘 / Akihiro Kubota

2022.05.13

アンクリエイティブ・コーディングとは、デザイナーが自由にコーディングできる権利のこと。「アンクリエイティブ・コーディング権」は、クリエイティブ・コモンズで保護されている。
イライザペンシル※1

UbuWebを立ち上げたアメリカの詩人ケネス・ゴールドスミスは、2011年の著書『Uncreative Writing – Managing Language in the Digital Age※2』のイントロダクションを、このような問いかけから始める。

In 1969 the conceptual artist Douglas Huebler wrote, “The world is full of objects, more or less interesting; I do not wish to add any more.” I’ve come to embrace Huebler’s ideas, though it might be retooled as “The world is full of texts, more or less interesting; I do not wish to add any more.”
(1969年、コンセプチュアル・アーティストのダグラス・ヒューブラーは、「世の中には、多かれ少なかれ面白いモノがすでにたくさんある。もうこれ以上、増やしたくはない」と書いた。私はこのヒューブラーの考えを受け入れた上で、さらにこの言葉を「世の中には、多かれ少なかれ面白いテキストがすでにたくさんある。もうこれ以上、増やしたくはない」と改変したくなる。)

この背景には、コンピュータやネットワークのような、デジタル環境によって生まれた、テキストの量的な氾濫という状況がある。だとすれば、今日の文化的ソフトウェアの氾濫によって「世の中には、多かれ少なかれ面白いコードがすでにたくさんある。もうこれ以上、増やしたくはない」といいたくなる人もいるだろう。

ポスト・インターネット・ポエトリー

ケネス・ゴールドスミスは、あらゆるテキストが詩になり得るとする。その事例として『Uncreative Writing』の中では、単純な反復や、偶然性に根ざしたダダの詩、あるいはコンクリート・ポエトリーやコンセプチュアル・アートにおけるテキストだけでなく、エラー、グリッチ、文字化け、ヘッダー、フォーマット変換から、RGBや座標を用いたコード表現やコンピュータ詩など、デジタルメディアによって出現した、さまざまな形態のテキストをとりあげる。それらは、広義のアプロプリエーション、コラージュ、サンプリング&リミックス(コピー&ペースト)、手続き的な生成と変換の事例である。言語をそれが表現する意味内容よりも、形式的、素材的な特徴から捉え、その創造ではなく、操作の可能性を探究する。書くという作業を、言葉を生み出すことではなく、言葉をある場所から別の場所に移動させる行為と捉え、無価値な選択や配置こそが新しいコンテンツになるとする[付録1]

図1[図1]公共空間に出現したコンピュータ・コンソールのエラー画面(という非創造的な詩)の写真を集めたFlickrサイト「Public Computer Errors※3

例えば、ケネス・ゴールドスミスが、ポストインターネット詩として取り上げている※4、サム・リヴィエールの『Kim Kardashian’s Marriage※5』は、そのタイトルから想像されるものとは異なり、(2022年4月30日に開催されたホワイトハウス記者会主催の夕食会にも出席した※6、お騒がせセレブの)キム・カーダシアンのソーシャルメディアの記事やゴシップサイトから抜粋されたテキストが用いられているわけではない。キム・カーダシアンとクリス・ハンフリーズの、2011年8月10日から72日間続いた結婚生活の内実とも関係がない。もちろん、2014年から約7年間続いた、カニエ・ウェストとの結婚生活ともまったく関係はない。その代わりに、この詩集に収められた、独白的にもみえる(カーダシアンとクリスハンフリーズの結婚期間の日数に等しい)72の詩の内容は、ウェブ詩のプロジェクトであったリヴィエールの前作『81 Austerities』の各タイトルをキーワードとして得られた、Google検索の上位10件の結果を再構成したものである。この詩には、自分の言葉は一切加えられていない。さらに、72の詩を7つずつ、8つの章にまとめる「Primer」「Contour」「Highlight」「Powder」「Blend」「Shadow」「Liner」「Gloss」の各タイトルは、カーダシアンの化粧のプロセスにちなんでいる(このサム・リヴィエレの詩の作り方を実装したコード詩をRuby+RDocで書いてみた※7)。

その最初の章「Primer」は、このような詩から始まる。

spooky berries

Edgar Allan Poe
has written a very eerie poem this month
with many allusions to the latest botanical blogging.

A very cute hand
carved natural pumpkin
hanging about 6.5 ft in the air,

and my little lens wasn’t cutting it.
So I popped on my big lens
and got it all.

不気味な木の実

エドガー・アラン・ポーが今月、
最新の植物ブログを連想させる、
とても不気味な詩を書いた。

とてもかわいい手彫りの天然カボチャが
6.5フィートほど宙吊りになっていて、

私の小さなレンズで撮影するのは無理だった。
だから、大きなレンズを付けて、全体を撮った。

こうした「非創造的(uncreative)」な文学、あるいは、マージョリー・パーロフのいう「非独創的な(unoriginal)」天才という概念は、広く社会に流布している「孤高の天才」のような、ロマンティックなイメージを無効にする。今日のデジタルメディアの時代においては、ラテン語の「gignere(生み出す)」と「generare(生成する)」を語源とする「天才(genius)」は、創造性や独創性の概念に背を向け、既存のもの、すでに利用可能なものから何かを作る者へと移り変わる。

この「非創造的」な創作という態度は、今日「技術の奴隷化」といわれているものを虚無的に、あるいは嫌々ながら受け入れることではない。むしろ、創作を技術に委ねることで、作家と鑑賞者の関係を反転し、人間を創造性や独創性という強迫観念から自由にする。それは同時に、近代人のエゴイズムやナルシシズム、あるいは作家のヒロイズムや伝説を批判的に解体する。修練して身につけた技を見せよう、他の人とは異なることをやろう、という凡庸な意図とは無関係の表現ならぬ出力は、軽やかで人におもねることなく、逆に清々しく感じられるほどだ。

しかしそれと同時に、非創造的であろうとすればするほど、エラーやランダムなど、どのような無作為な方法を用いても、自己表現を消去するのが不可能であることも、改めて明らかになる。すでにある文書をそのまま入力し直すような、あるいはGoogle検索の結果を並べるだけのような、一見「非創造的」な作業を行うだけでも、私たちはさまざまな方法で、無意識の内に「意味」を込めようとしたり、「自分」を表現しようとしてしまう。選択やフィルタリング、あるいはミュートやブロックが、メディア環境によって作り上げられた、ある種の偶然に他ならないとしても、人はそこに主体性や自由意志を見ようとする。私たちは、創造的であろうとすることから、それがたとえ近代の幻想であったとしても、プロパガンダや広告によって植え付けられたものであったとしても、決して逃れることはできない。だから逆に「非」創造的であろうとすることで、自己表現や創造性、独創性という、人を暗黙の内に縛りつけている、不可視で不可避なフレームの存在から、意図的に距離を置こうとする。

GitHub Copilot登場!

コンピュータのプログラムコードも、テキストの一種である。それは人間のためというよりも、どちらかといえば、コンピュータという非人間の読者のために書くテキストである。コンピュータはそのテキストを読み込んで実行する。しかし時として、図1の「Public Computer Errors」のように、うまく実行できなくなることもある。そうした時、インターフェイスの内側に隠されていたコンピュータの内部が突如露わになり、コンピュータは詩人ならぬ詩機械(Poetry Machine)となる。遍在するコンピュータの中で、実行し続けている不可視のプログラムコードは、今日における「機械の中のゴースト」ともいえるだろう。

テキストと同じように、非創造的なコーディング、すなわち「アンクリエイティブ・コーディング」を行ってみる。とはいえ、一般のテキストは自由な操作や編集によって、多少文法的、用語的な誤りがあっても、それを詩的言語として機能させれば、多様なイメージとメタファーを生み出してくれる。しかし、コードにエラーがあれば、それをそのまま実行することはできない。残念ながら、今日のコンピュータはまだコードを詩的に解釈することはできない。実行できないコードを、演奏できない楽譜のようなコンセプチュアル・コードと呼ぶこともできるが、むしろそれは、意味の接合を拒否する言語詩(Language Poetry)のような、テキスト一般として捉える方がいいだろう。

この非創造的コーディングを、GitHub Copilot※8を使って実践してみる。GitHub Copilotとは、人工知能(AI)を研究する非営利団体OpenAIが開発しているOpenAI Codexを用いた、コードの自動生成システムである。特に、GitHub上に公開されている大量のコードを学習することで、Copilotは入力されたコメントやコードに関する情報のコンテキスト(パターン)に基づく生成結果を提示する。現在はまだテクニカル・プレビューの段階ではあるが、Visual Studio Codeのようなコードエディタの拡張機能を通じて、簡単に使用することができる[図2]。

図2[図2]GitHub CopilotとVisual Studio Codeを用いたp5.jsによるアンクリエイティブ・コーディング環境。18行目のグレイのコードがCopilotによって提案されている。

Copilotには

  • コメントの内容からコードを生成する
  • アルゴリズムの例示からコードを生成する
  • コードを別言語に翻訳する

といった機能がある。面白いのは、これまではプログラムコードの外側にあった、人間のためのコメントを、コンピュータが積極的に解釈し、コードの生成に利用していることである。そうすることで、プログラムという「事前に」(pro-)「書いたもの」(-gram)が、これから書かれるもの(post-gram)となり、コードの内部(実行される部分)と外部(実行されない部分)の境界も曖昧になる。任意のコメントから実行可能なコードを生成することは、コンピュータの側から見れば、コメントを事後的に解釈して拡張することであり、これはコンピュータにとっての、ポエティック・コーディングであるともいえる。もちろんその一方で、機械学習のデータセットとして公開コードを利用することは、コピーと生成の境界も曖昧にするため、Copilotは学習したコードの著作権を侵害するリスクを生み※9、他の機械学習の事例と同様に、そこにはさまざまなバイアスが含まれる。しかしこうした外部のテキストやコードの非制御的な利用こそが、非創造的なライティングや、そこでの引用やアプロプリエーションの問題と重なってくる。

コーディングの初心者に対する事例として用いられる“hello world※10”を出力するプログラムにおいて、コンピュータにとって意味があるのはmain()やprintf()という実行される関数であるが、同じくコードに含まれる、“hello”や“world”という、コンピュータが直接解釈しない語や文にも、別の重要な意味がある。なぜそれが“hello”であり、“world”なのか。それはいつどこから始まり、なぜこんなにも有名になったのか。さまざまな言語やバージョンに、どのように派生していったのか。意味がないはずのメタ構文変数としての“foo”や“bar”(日本の場合は“hoge”や“piyo”)にも、そして正しく実行されれば良いだけの関数の名前にも、今やそのシニフィエとして、さまざまな文化的来歴が畳み込まれている。コメントの内容が、コードを読み書きする私たち人間にとって重要な意味を持っているように、機械学習から生成されたコードも、単なるコンピュータへの命令を超えて、人間社会や、物質文化に対するジェスチャーを(再帰的に)持つ(面白いことに、Copilotが自動的にコメントを生成することもある)。

アンクリエイティブ・コーディングを実践する

Copilotが提示するコードは、膨大な学習データから切り取られ、自動的に移動、編集されながら、なおかつ(ほとんどのものが)実行可能であるという点で、補完ツールやリファレンスとも、サンプルコード集とも異なるユニークなものである。『Uncreative Writing』には「LANGUAGE AS MATERIAL(素材としての言語)」という章があり、そこでは、言語をコミュニケーションのメディアとしてではなく、その形式的な性質に注目し、言語を様々な状態やデジタル・テキストの生態系の中で動き回り、変形し続ける素材とみなす。言語を素材とみなすことで、言語を著者や固有の意味から一旦切り離し、中性化しようとする。抽象主義の画家たちが、絵画からイリュージョンやメタファーを取り除くために、具体物ではなく幾何学的な形態を選んだように、ダダの詩人が音の響きだけで詩を成り立たせようしたり、文字の幾何学的形状によって具体詩がつくられたように。

Processingを最初に設計、実装したベン・フライとケイシー・リースも、事あるごとに「CODE AS MATERIAL(素材としてのコード)」と語っている[付録2]。しかし彼らにとっての素材とは、ゴールドスミスがいうようなアルゴリズムやコードの中立性ではなく、それぞれのプログラミング言語が有している、固有の特徴のことを指している。プログラマーは、それぞれの好みや目的に合わせて、その時々に適した素材(プログラム言語)を選択すると同時に、選択した素材によって思考やコーディングにバイアスをかける。素材というのは、そこからさまざまなものが生み出し得るという、ゴールドスミスの視点からは中立だが、その本性にさまざまな制約や方向性が不可避に含まれるという意味では、フライとリースがいうように固有のものである。素材は、中立性と固有性の結節点なのだ。

フライやリースが推奨しているのは、事前に仕様を明確にし、それを正しく実装するようなスタイルのプログラミングではない。彼らはプログラムのことをスケッチと呼び、ノートに鉛筆でドローイングをしていくように、コードという素材を用いてアイデアを探究し、コードを少しずつ変化させながら、アイデアを発展させていく。『Uncreative Writing』の最後の章のタイトルが「PROVISIONAL LANGUAGE(暫定的な言語)」であるように、コードもテキスト同様、常に可変的、暫定的な生態系の中で生きている。それは日々アップデートされ、自らが変化していくと同時に、ハードウェアのような環境の更新にも対応し、さらに時として、別のバージョンへと分岐(fork)していく。

『Being Material※11』におけるフライとリースの事例に倣って、一つの円のスケッチが、どのようにCopilotによって、非創造的に発展していくのかを見ていきたい。まずは、このコードから出発する(今回はProcessingではなく、Javascriptのライブラリ化された、p5.js※12を用いる)。

function setup() {
    createCanvas(400, 400);
}
function draw() {
    background(255);
    ellipse(200, 200, 280, 280);
}

実行すると、以下のような出力が得られる。

図3

コメントを入れずに、このコードをCopilotによって拡張する。円を描く関数の半径が、等差的に小さくなりながら増殖していくことで、同心円が描かれる。これは、Copilotの環世界(umwelt)の一端でもある。

function setup() {
    createCanvas(400, 400);
}
function draw() {
    background(255);
    ellipse(200, 200, 280, 280);
    ellipse(200, 200, 250, 250);
    ellipse(200, 200, 220, 220);
    ellipse(200, 200, 180, 180);
    ellipse(200, 200, 140, 140);
    ellipse(200, 200, 100, 100);
    ellipse(200, 200, 60, 60);
    ellipse(200, 200, 20, 20);
}

図4

全体を再生成すると、今度は以下のようなコードになった。白と黒で交互に塗りつぶしながら、等比的に半径が縮小していく。

function setup() {
    createCanvas(400, 400);
}
function draw() {
    background(220);
    stroke(0);
    strokeWeight(2);
    noFill();
    ellipse(200, 200, 300, 300);
    fill(0);
    ellipse(200, 200, 200, 200);
    fill(255);
    ellipse(200, 200, 100, 100);
    fill(0);
    ellipse(200, 200, 50, 50);
    fill(255);
    ellipse(200, 200, 25, 25);
    fill(0);
    ellipse(200, 200, 12.5, 12.5);
    fill(255);
    ellipse(200, 200, 6.25, 6.25);
}

図5

「さまざまな色を描画する」というコメントを入れると、カラフルな同心円が生成された。

function setup() {
    createCanvas(400, 400);
}
// さまざまな色を描画する
function draw() {
    background(255);
    stroke(0);
    ellipse(200, 200, 280, 280);
    fill(0, 0, 0);
    ellipse(200, 200, 260, 260);
    fill(255, 0, 0);
    ellipse(200, 200, 240, 240);
    fill(0, 255, 0);
    ellipse(200, 200, 220, 220);
    fill(0, 0, 255);
    ellipse(200, 200, 200, 200);
    fill(255, 255, 0);
    ellipse(200, 200, 180, 180);
    fill(255, 0, 255);
    ellipse(200, 200, 160, 160);
    fill(0, 255, 255);
    ellipse(200, 200, 140, 140);
    fill(255, 255, 255);
    ellipse(200, 200, 120, 120);
    fill(0, 0, 0);
    ellipse(200, 200, 100, 100);
    fill(255, 0, 0);
    ellipse(200, 200, 80, 80);
    fill(0, 255, 0);
    ellipse(200, 200, 60, 60);
    fill(0, 0, 255);
    ellipse(200, 200, 40, 40);
    fill(255, 255, 0);
    ellipse(200, 200, 20, 20);
}

図6

「形をずらす」というコメントを追加すると、対角線上に異なる色の円が並ぶ。

function setup() {
    createCanvas(400, 400);
}
// さまざまな色を描画する
// 形をずらす
function draw() {
    background(220);
    stroke(0);
    strokeWeight(2);
    fill(255, 0, 0);
    ellipse(50, 50, 50, 50);
    fill(0, 255, 0);
    ellipse(100, 100, 50, 50);
    fill(0, 0, 255);
    ellipse(150, 150, 50, 50);
    fill(255, 255, 0);
    ellipse(200, 200, 50, 50);
    fill(255, 0, 255);
    ellipse(250, 250, 50, 50);
    fill(0, 255, 255);
    ellipse(300, 300, 50, 50);
    fill(255, 255, 255);
    ellipse(350, 350, 50, 50);
    fill(0, 0, 0);
    ellipse(400, 400, 50, 50);
}

図7

同じコメントから、別のコードも生成された。RGBのそれぞれをオンオフすることから生まれる8通りの色が、3×3の9マスに順に配置されていく(白の円は背景色と同じなので見えない)。

function setup() {
    createCanvas(400, 400)
}
// さまざまな色を描画する
// 形をずらす
function draw() {
    background(255);
    noStroke();
    fill(0, 0, 0);
    ellipse(100, 100, 100, 100);
    fill(255, 0, 0);
    ellipse(200, 100, 100, 100);
    fill(0, 255, 0);
    ellipse(300, 100, 100, 100);
    fill(0, 0, 255);
    ellipse(100, 200, 100, 100);
    fill(255, 255, 0);
    ellipse(200, 200, 100, 100);
    fill(0, 255, 255);
    ellipse(300, 200, 100, 100);
    fill(255, 0, 255);
    ellipse(100, 300, 100, 100);
    fill(255, 255, 255);
    ellipse(200, 300, 100, 100);
    fill(0, 0, 0);
    ellipse(300, 300, 100, 100);
}

図8

「形を動かす」というコメントを入れると、円がマウスポインターの位置に追従する、インタラクティヴなコードが生成される。

function setup() {
    createCanvas(400, 400);
}
// 形を動かす
function draw() {
    background(255);
    noStroke();
    fill(0);
    ellipse(mouseX, mouseY, 50, 50);
}

図9

コメントが具体的になると、そのまま実装しようとする。「たくさんの」は、100個と解釈され、ここで初めて繰り返しループが登場した。

function setup() {
    createCanvas(400, 400);
}
// たくさんの円を描き、それぞれの色をランダムに決める
function draw() {
    background(220);
    noStroke();
    for (var i = 0; i < 100; i++) {
        var x = random(width);
        var y = random(height);
        var r = random(20, 50);
        fill(random(255), random(255), random(255));
        ellipse(x, y, r, r);
    }
}

図10

形ではなく「さまざまな色による文字列を描く」というコメントにすると、文字列として“Hello, world!”が選ばれた。

function setup() {
    createCanvas(400, 400);
}
// さまざまな色による文字列を描く
function draw() {
    background(220);
    fill(0, 0, 0);
    textSize(32);
    text("Hello, world!", 10, 50);
    fill(255, 0, 0);
    text("Hello, world!", 10, 100);
    fill(0, 255, 0);
    text("Hello, world!", 10, 150);
    fill(0, 0, 255);
    text("Hello, world!", 10, 200);
    fill(255, 255, 0);
    text("Hello, world!", 10, 250);
    fill(255, 0, 255);
    text("Hello, world!", 10, 300);
    fill(0, 255, 255);
    text("Hello, world!", 10, 350);
}

図11

コメントを「さまざまな色と文字列を描画する」と少し変えるだけで、出力も変化する。Copilotは甘いもの好きのようだ。

function setup() {
    createCanvas(400, 400);
}
// さまざまな色と文字列を描画する
function draw() {
    background(255);
    fill(0);
    textSize(32);
    text("Hello, world!", 10, 50);
    fill(255, 0, 0);
    textSize(16);
    text("I like cake.", 10, 100);
    fill(0, 0, 255);
    textSize(12);
    text("It is delicious.", 10, 150);
    fill(0, 255, 0);
    textSize(24);
    text("I like donuts.", 10, 200);
    fill(255, 255, 0);
    textSize(36);
    text("Cake is yummy!", 10, 250);
}

図12

次に、使用する関数を指定してから、その後どのようなコードが生成されるのかを試してみる。背景とストロークを設定してから、コメントは挿入せずにbeginShape();の先のコードを生成すると以下のようになった。ノイズ関数の繰り返しのため、実行するたびに少しずつ異なる図形が表示される。

function setup() {
    createCanvas(400, 400);
}
function draw() {
    background(0);
    stroke(255);
    strokeWeight(2);
    noFill();
    beginShape();
    for (var i = 0; i < width; i++) {
        var x = map(i, 0, width, 0, width);
        var y = map(noise(x), 0, 1, 0, height);
        vertex(i, y);
    }
    endShape();
}

図13

次に、関数arc()のサンプルコード※13の続きを生成する。分割され、ずらされた円弧が、外側に増殖していく。

function setup() {
    createCanvas(400, 400);
}
function draw() {
    background(255);
    stroke(0);
    translate(150, 150);
    arc(50, 55, 50, 50, 0, HALF_PI);
    noFill();
    arc(50, 55, 60, 60, HALF_PI, PI);
    arc(50, 55, 70, 70, PI, PI + QUARTER_PI);
    arc(50, 55, 80, 80, PI + QUARTER_PI, TWO_PI);
    arc(50, 55, 90, 90, 0, PI + QUARTER_PI);
    arc(50, 55, 100, 100, 0, PI);arc(50, 55, 110, 110, PI, TWO_PI);
    arc(50, 55, 120, 120, PI + QUARTER_PI, TWO_PI);
    arc(50, 55, 130, 130, 0, PI + QUARTER_PI);
    arc(50, 55, 140, 140, 0, PI);
    arc(50, 55, 150, 150, PI, TWO_PI);
    arc(50, 55, 160, 160, PI + QUARTER_PI, TWO_PI);
    arc(50, 55, 170, 170, 0, PI + QUARTER_PI);
    arc(50, 55, 180, 180, 0, PI);
    arc(50, 55, 190, 190, PI, TWO_PI);
    arc(50, 55, 200, 200, PI + QUARTER_PI, TWO_PI);
    arc(50, 55, 210, 210, 0, PI + QUARTER_PI);
    arc(50, 55, 220, 220, 0, PI);
    arc(50, 55, 230, 230, PI, TWO_PI);
    arc(50, 55, 240, 240, PI + QUARTER_PI, TWO_PI);
    arc(50, 55, 250, 250, 0, PI + QUARTER_PI);
    arc(50, 55, 260, 260, 0, PI);
    arc(50, 55, 270, 270, PI, TWO_PI);
    arc(50, 55, 280, 280, PI + QUARTER_PI, TWO_PI);
    arc(50, 55, 290, 290, 0, PI + QUARTER_PI);
    arc(50, 55, 300, 300, 0, PI);
    arc(50, 55, 310, 310, PI, TWO_PI);
    arc(50, 55, 320, 320, PI + QUARTER_PI, TWO_PI);
    arc(50, 55, 330, 330, 0, PI + QUARTER_PI);
    arc(50, 55, 340, 340, 0, PI);
}

図14

関数bezier()の引数を生成すると、マウスに追従して蠢く曲線を描画するコードになった。シンプルなコードだが、動きはかなり面白い(ので、実際に実行してみて欲しい)。

function setup() {
    createCanvas(windowWidth, windowHeight);
}
function draw() {
    background(0);
    stroke(255);
    strokeWeight(1);
    noFill();
    bezier(
        mouseX, mouseY,
        mouseX + random(-100, 100), mouseY + random(-100, 100),
        mouseX + random(-100, 100), mouseY + random(-100, 100),
        mouseX + random(-100, 100), mouseY + random(-100, 100)
        );
    }

図15

円を描くところまで入力し、その後コメント行を表す「//」だけを入力すると、コメントの続きと、それに応じた形状関数を生成する。最後には、再び“Hello World”が現れる。

function setup() {
    createCanvas(400, 400);
    noLoop();
}
function draw() {
    background(255);
    stroke(0);
    strokeWeight(1);
    // Draw the circle
    ellipse(200, 200, 300, 300);
    noFill();
    // Draw the lines
    line(100, 100, 300, 300);
    line(100, 300, 300, 100);
    // Draw the points
    point(100, 100);
    point(100, 300);
    point(300, 100);
    point(300, 300);
    // Draw the rectangles
    rect(100, 100, 100, 100);
    rect(100, 300, 100, 100);
    rect(300, 100, 100, 100);
    rect(300, 300, 100, 100);
    // Draw the triangles
    triangle(100, 100, 300, 100, 200, 300);
    triangle(100, 300, 300, 300, 200, 100);
    // Draw the arcs
    arc(200, 200, 100, 100, 0, PI);
    arc(200, 200, 100, 100, PI, TWO_PI);
    // Draw the bezier curves
    bezier(100, 100, 300, 100, 200, 300, 100, 300);
    bezier(100, 300, 300, 300, 200, 100, 300, 100);
    // Draw the quadratic curves
    quad(100, 100, 300, 100, 200, 300);
    quad(100, 300, 300, 300, 200, 100);
    // Draw the curves
    curve(100, 100, 300, 100, 200, 300, 100, 300);
    curve(100, 300, 300, 300, 200, 100, 300, 100);
    // Draw the text
    text("Hello World", 100, 100);
    text("Hello World", 100, 300);
    text("Hello World", 300, 100);
    text("Hello World", 300, 300);
}

図16

「There is always light behind the clouds.」という、ルイザ・メイ・オルコット※14の格言をコメントにすると、「雲」「太陽」「太陽の光」というコメントが入ったコードを生成した。まさに格言のミニマルな幾何学的描写である。

function setup() {
    createCanvas(400, 400);
}
//There is always light behind the clouds.
function draw() {
    background('black');
    fill('white');
    noStroke();
    //Clouds
    ellipse(100, 100, 100, 100);
    ellipse(150, 100, 100, 100);
    ellipse(200, 100, 100, 100);
    ellipse(250, 100, 100, 100);
    ellipse(300, 100, 100, 100);
    ellipse(350, 100, 100, 100);
    //Sun
    fill('yellow');
    ellipse(50, 50, 100, 100);
    //Sun rays
    stroke('yellow');
    line(50, 50, 100, 100);
    line(50, 50, 75, 75);
    line(50, 50, 75, 25);
}

図17

前述のサム・リヴィエールの詩「spooky berries」をコメントに入れると、原稿執筆の際に参照していた、ケネス・ゴールドスミスの詩「The Weather – Spring※15」の冒頭部分が出力されるコードが生成された。Copilotはローカルな記憶を保持している。

function setup() {
    createCanvas(400, 400);
}
// spooky berries Edgar Allan Poe has written a very eerie poem this month with many allusions to the latest botanical blogging. A very cute hand carved natural pumpkin hanging about 6.5 ft in the air, and my little lens wasn't cutting it. So I popped on my big lens and got it all.
function draw() {
    background(220);
    noStroke();
    fill(0, 0, 0);
    textSize(20);
    text("Oh, we are looking at, uh, weather, uh, across, uh, Iraq obviously here for the next several days, uh, we have, uh, actually some good, good weather is expected.", 20, 20, 360, 360);
}

図18

コーディングが写真と出会うとき

ゴールドスミスは、インターネットやウェブにより、テキストが写真やコラージュと出会ったことで、非創造的なライティングが拡大したという。だとすれば、Copilotのような機械学習によって、コードも同じように、写真と出会ったといえるだろう。リースとフライは、コーディングを1行1行、すなわち1本1本線を描いていく、手書きのドローイングやスケッチに喩えたが、Copilotを用いると、リターンキーを押すだけで、一瞬にしてコードの全貌が現れる。それは、シャッターを押せば画面全体が一度に現れる、写真撮影の際の感覚と良く似ている。

デジタル写真のコラージュを、バイナリーデータのまま行うことは難しい。しかしデータを視覚化、すなわち人間の知覚レベルにおいて機能するようにすれば、それをさまざまな形式に変形したり分解、接続することができる。同様に、プログラムコードをテキストレベルで、自動的、無作為に編集することは難しいが、機械学習というパターンの収集によって、プログラムコードを動くまま、つまり生きたまま操作することが可能になる。機械学習を用いてコーディングするということは、写真が現実世界の画像を自動化したように、さらにその写真を機械やソフトウェアが自動撮影したり自動処理するように、つまり非人間写真※16のようにコーディングすることともいえるだろう。機械学習によって生まれた非創造的なコーディングは、コードを中性化し、AI時代のコーダーの意味や役割を問いかける。

そもそも、同じアルゴリズムに対して、なぜ別のコードを書く必要があるのか。アルゴリズムとコードは、どこまでが同じで、どこからが異なるものなのか。アルゴリズムのエレガントなインプリメンテーションを求めない、アンクリエイティブ・コーディングは、アルゴリズムの洗練や抽象を求めないという意味で、最小美学(ミニマル・エステティック)的である。同時に、その出力(実行結果)の美しさや華麗さを求めないという意味で、最小網膜(ミニマル・レティナ)的でもある。コードの支配を放棄したアンクリエイティブ・コーダーは、アルゴリズムや出力ではなく、否応なくコードそのものを見つめるようになる。コーダーは意図せず生成されたコードを読み、その読みの経験を前景化する。理解や感性、そして正しさや実用性から切り離されたコードは、美学的でも政治的でもなく、アバンギャルドでも保守的でもなく、純粋に、そして必然的に詩的であろうとすることで、たとえそうでなくとも、コードの体験を剥き出しにする。

科学や工学におけるプログラムコードは、それが想定通りに動くか、そして停止するか、あるいは効率よく実行できるか、再利用できるかといった、主にコードの形式的、機能的、生産的な側面に着目する。しかしながら、コンピュータが読んで実行するためだけでなく、人間のためのものともして、二重に存在している高級言語で書かれたコードには、コードの人間的な解釈や使用、さらには社会的な美学や政治といったイデオロギーやパラダイムが否応なく入り混む。さらには、コードそのものが持つエージェンシーによって、人間でも機械でもない、もうひとつの素材としてのコードの経験が上演される。しかし、機械の経験から生み出された非人間的コードとそのパフォーマティヴィティは、主体の前に突如現れ、瞬く間(実行時間)にそれを超えていく。そこに残るのは、叙事でも叙情でもなく、実利的な効率や汎用性、超越的な洗練や強度でもなく、「このコードは動く」という実行の目撃とその痕跡だけである。

膨大なコードを学習したコンピュータと、コードを書かない人間の共同作業というアンクリエイティブ・コーディングは、機械学習のコーディングへの応用というコンピュータ・サイエンスにも、コードの人文的読解によるクリティカル・コード・スタディーズにも、そして芸術表現としてのクリエイティブ・コーディングのいずれにも属さない、無計画の散歩のような曖昧な立ち位置によって、そのいずれとも関係を持つ。非創造的で、非人間的なコーディングは、人間の主体性や、表現の社会的機能に対する疑いを、コーダーの背後にそっと置くことで、他者との違いを強調する自己表現や、人を驚かしたり、人から賞賛を得ることを目的とするような、コードの人間化に対する、予期せぬ抵抗と反乱を体現する。それは同時に、非機能の労働的価値を許容する、現代社会のポストヒューマニズム的状況を写像しながら反転、逸脱していくような、目的なき裸のコーディング実践でもある。

[付録1]

“UNCREATIVITY AS A CREATIVE PRACTICE※17” (創造的実践としての非創造性)

I am spending my 39th year practicing uncreativity.

私は39回目の年を、非創造を実践しながら過ごしています。

On Friday, September 1, 2000, I began retyping the day’s New York Times, word for word, letter for letter, from the upper left hand corner to the lower right hand corner, page by page. Today, November 10, 2000, I am approximately half way through the project. I intend to finish by New Year’s Day.

2000年9月1日(金)、私はその日のNew York Timesを一字一句、左上から右下へ、1ページずつ打ち直し始めました。今日、2000年11月10日で、このプロジェクトの約半分が終了しました。元旦までに完成させるつもりです。

The object of the project is to be as uncreative in the process as possible. It’s one of the hardest constraints an artist can muster, particularly on a project of this scale; with every keystroke comes the temptation to “fudge,” “cut-and-paste,” and “skew” the mundane language. But to do so would be to foil the exercise.

このプロジェクトの目的は、制作のプロセスにおいて可能な限り創造性を発揮しないことです。特にこの規模のプロジェクトの場合、これはアーティストにとって最も困難な制約のひとつです。キーを打つたびに、「ごまかしたい」「切り貼りしたい」「ありふれた言葉を歪めたい」という誘惑に駆られるのです。しかし、それをやってしまうと、せっかくの練習が台無しになってしまいます。

I’ve long been an advocate of extreme process writing–recording every move my body has made in a day, recording every word I spoke over the course of a week, recording every sound I heard ending in the sound of “r” for almost four years–but never have I faced a writing process this dry, this extreme, this boring.

私は長い間、極端なプロセス・ライティングを提唱してきました。1日の自分の体のすべての動きを記録し、1週間に話したすべての言葉を記録し、4年近く「r」の音で終わる音のすべてを記録しました。しかし、ここまでドライで過激でつまらない執筆プロセスに直面したことは、一度もありませんでした。

John Cage said “If something is boring after two minutes, try it for four. If still boring, then eight. Then sixteen. Then thirty-two. Eventually one discovers that it is not boring at all.”

ジョン・ケージは「2分でつまらないものは、4分やってみろ」と言いました。「それでもつまらなければ、8分。そして16分。そして32分。やがて人は、それがまったく退屈でないことを発見する」と。

I’m interested in a valueless practice. Nothing has less value than yesterday’s news (in this case yesterday’s newspaper–what could be of less value, say, than stock quotes from September 1, 2000?). I’m interested in quantifying and concretizing the vast amount of “nutritionless” language; I’m also interested in the process itself being equally nutritionless.

私は無価値な行為に興味があります。昨日のニュースほど価値のないものはありません(例えば昨日の新聞、2000年9月1日の株価より価値のないものがあるでしょうか)。私は、膨大な量の「栄養のない」言葉を定量化し、具体化することに興味があります。また、そのプロセス自体も同様に無栄養であることに興味があります。

Retyping the New York Times is the most nutritionless act of literary appropriation I could conceive of. Had I instead, for example, retyped Ulysses, there would have been too much value, for Ulysses, as we all know, is a very valuable book.

New York Timesを再入力することは、私が考えうる限り最も栄養のない文学的流用行為です。例えば、私が『ユリシーズ』を再入力していたとすれば、それはあまりにも価値がありすぎたでしょう。『ユリシーズ』は、誰もが知っているように、とても価値のある本ですから。

I took inspiration from Warhol’s “Empire,” his “unwatchable” 24-hour film of the Empire State Building. Similarly, imagine a book that is written with the intention not to be read. The book as object: conceptual writing; we’re happy that the idea exists without ever having to open the book.

私は、エンパイア・ステート・ビルを24時間撮影したウォーホルの『エンパイア』からヒントを得ました。同様に、読まれないことを意図して書かれた本を想像してみてください。オブジェクトとしての本:コンセプチュアル・ライティング。私たちは、アイデアが存在していることに、本を開くことなく満足しているのです。

Innovative poetry seems to be a perfect place to place a valueless practice; as a gift economy, it is one of the last places in late hyper-capitalism that allows non-function as an attribute. Both theoretically and politically, the field remains wide open.

革新的な詩は、無価値な実践を行うのに完璧な場所であるように思えます。それは贈与経済として、非機能を属性として許容する後期超資本主義における、最後の場所の一つなのです。理論的にも政治的にも、この分野はまだ広く開かれています。

But in capitalism, labor equals value. So certainly my project must have value, for if my time is worth an hourly wage, then I might be paid handsomely for this work. But the truth is that I’ve subverted this equation by OCR’ing as much of the newspaper as I can.

しかし、資本主義では、労働は価値に等しいのです。だから確かに私のプロジェクトには価値があるはずです。私の時間が時給に値するなら この仕事に対して高額な報酬が支払われるかもしれません。しかし実は、私は新聞をできるだけOCRすることで、この等式を覆してきたのです。

Almost 100 years ago, the visual arts came to terms with this issue in Duchamp’s “Urinal.” Later, Warhol, then Koons extended this practice. In music we have vast examples from John Oswald’s Plunderphonics to the ubiquitous practice of sampling. Where has literature been in this dialogue? One hundred years after Duchamp, why hasn’t straight appropriation become a valid, sustained or even tested literary practice?

約100年前、デュシャンの「便器」で視覚芸術はこの問題に向き合いました。その後、ウォーホル、そしてクーンズがこの実践を拡大しました。音楽では、ジョン・オズワルドのプランダーフォニックスからサンプリングというユビキタスな実践に至るまで、膨大な事例があります。文学はこの対話の中で、一体どこにいたのでしょうか?デュシャンの100年後、なぜストレートなアプロプリエーションは、有効で持続的な、あるいは試される文学的実践とならなかったのでしょうか。

John Cage, whose mission it was to accept all sound as music, failed; his filter was on too high. He permitted only the sounds that fell into his worldview. Commercial sounds, pop music, lowbrow culture, sounds of violence and aggression, etc. held no place in the Cagean pantheon; certainly, nutritionlessness was not what we would consider a Cagean attribute.

ジョン・ケージは、すべての音を音楽として受け入れることをその使命としていましたが、彼のフィルターが高すぎたために失敗しました。彼は、自分の世界観に合う音しか認めませんでした。商業的な音、ポップミュージック、低俗な文化、暴力や攻撃性のある音などは、ケージの殿堂には含まれません。確かに、無栄養性はケージの特質とは言えません。

However, if John Cage theoretically claimed that any sound can be music, then we logically must conclude that, properly framed, any language can be poetry.

しかし、ジョン・ケージが「どんな音でも音楽になりうる」と理論的に主張したのであれば、論理的には「どんな言語でも適切に枠組みされれば詩になりうる」と結論づけなければなりません。

When I reach 40, I hope to have cleansed myself of all creativity.

40歳になったら、すべての創造性を自浄したいと思います。

[付録2]

“Code as Material※18” (素材としてのコード)
Ben Fry and Casey Reas

“Being Material※19
Edited by Marie-Pier Boucher, Stefan Helmreich, Leila W Kinney, Skylar Tibbits, Rebecca Uchill and Evan Ziporyn

Every programming language is a distinct material. Physical materials like clay and wood have different properties, and the same is true of code materials. One programming language might work well for quickly writing a program to parse data, and another might be better suited to write software to control a robot sent to another planet. Some programming languages are good for general tasks, and others are created for specific domains.

プログラミング言語は、どれも個性的な素材です。粘土と木のような物理的な材料は異なる特性を持っていますが、コードの材料も同じです。あるプログラミング言語は、データを解析するプログラムを素早く書くのに適しているかもしれませんし、別のプログラミング言語は、他の惑星に送られるロボットを制御するソフトウェアを書くのに適しているかもしれません。プログラミング言語にも、一般的な作業に適したものと、特定の領域向けに作られたものがあります。

We created Processing in 2001 as a code material for the visual arts, and we have been working on it continuously for seventeen years. Processing is a material that is easy for beginners to work with and is comfortable and powerful for people with years of experience writing code. A program written in Processing is called a sketch; we emphasize the idea of writing code to explore ideas and to iterate using working code. One line of code can draw a circle on the screen, and a few more lines can create a working drawing program. With a few weeks of work, that same code could evolve to have all of the functionality of a professional drawing application.

私たちは2001年にビジュアルアートのためのコード素材としてProcessingを作り、17年間継続的に取り組んできました。Processingは、初心者にも扱いやすく、コードを書いた経験のある人にとっても快適で強力な素材です。Processingで書かれたプログラムはスケッチと呼ばれます。私たちは、アイデアを探求するためにコードを書き、動くコードを使って少しずつ改良していく、という考えを大切にしています。1行のコードで画面に円を描くことができ、さらに数行付け加えれば、動く描画プログラムを作成することができます。数週間も作業すれば、同じコードがプロの描画アプリケーションのすべての機能を持つように、進化させることができます。

Code is used to write software; therefore learning to write code makes it possible to invent new software. In the arts, as in the sciences, it is often necessary to invent software to do new things—to explore ideas that others have not yet pur- sued. Processing was created to be flexible to encourage a wide range of explorations and discoveries.

コードはソフトウェアを書くために使われます。ですから、コードを書けるようになれば、新しいソフトウェアを発明することが可能になります。芸術の世界でも、科学の世界と同じように、新しいことをするためにソフトウェアを発明することが必要な場合があります。Processingは、そのようなさまざまな探求や発見を促すために、柔軟に作られたものなのです。

The code and the images the code creates on the next few pages show the development of one sketch, a minimal image of a circle, through a few ideas that feature how the Processing language operates and the kind of thinking it encourages.

次のページでは、コードとコードが作成する画像から、1つのスケッチ、つまり最小限の1つの円の画像が、Processing言語がどのように動作し、どのような思考を促すかを特徴づけるいくつかのアイデアを通して発展していく様子をご覧いただけます。

[付録3]

{ソフトウェア}構造とウォールドローイング

ケイシー・リースのオンラインテキスト「{ソフトウェア}構造※20」の中で取り上げられている、ソル・ルゥイットのウォール・ドローイングの事例と、リースが示しているソフトウェア構造を指示(コメント)とする、アンクリエイティブ・コーディングを行ってみた。

ウォール・ドローイング#69

Lines not long, not straight, not touching, drawn at random using four colors, uniformly dispersed with maximum density, covering the entire surface of the wall.
(長くない線、直線でない線、接触していない線が、4色でランダムに描かれ、最大限の密度で均一に分散し、壁の全面を覆っている)

function setup() {
    createCanvas(400, 400);
}
//Lines not long, not straight, not touching, drawn at random using four colors, uniformly dispersed with maximum density, covering the entire surface of the wall.
function draw() {
    background(0);
    stroke(255);
    strokeWeight(1);
    for (var i = 0; i < width; i += 10) {
        for (var j = 0; j < height; j += 10) {
            var x1 = random(i, i + 10);
            var y1 = random(j, j + 10);
            var x2 = random(i, i + 10);
            var y2 = random(j, j + 10);
            line(x1, y1, x2, y2);
        }
    }
}

図19

色彩はモノクロームで、線は直線だが、ランダムな長さと向きの短い線が接触せずにキャンバスを覆い尽くす。

ウォール・ドローイング#63

A Wall is divided into four horizontal parts. In the top row are four equal divisions, each with lines in a different direction. In the second row, six double combinations; in the third row, four triple combinations; in the bottom row, all four combinations superimposed.
(壁が水平に4分割されている。最上段は4等分され、それぞれ異なる方向に線が引かれている。2列目には、6つの2重の組み合わせ、3列目には、4つの3重の組み合わせ、下段は、4つの組み合わせが重なっている)

function setup() {
    createCanvas(400, 400);
}
//A Wall is divided into four horizontal parts. In the top row are four equal divisions, each with lines in a different direction. In the second row, six double combinations; in the third row, four triple combinations; in the bottom row, all four combinations superimposed.
function draw() {
    background(220);
    stroke(0);
    strokeWeight(1);
    line(0, 0, width, 0);
    line(0, 0, 0, height);
    line(width, 0, width, height);
    line(0, height, width, height);
    line(0, height / 2, width, height / 2);
    line(0, height / 4, width, height / 4);
    line(0, height / 8, width, height / 8);
    line(0, height / 16, width, height / 16);
    line(0, height / 32, width, height / 32);
    line(0, height / 64, width, height / 64);
    line(0, height / 128, width, height / 128);
    line(0, height / 256, width, height / 256);
    line(0, height / 512, width, height / 512);
    line(0, height / 1024, width, height / 1024);
    line(0, height / 2048, width, height / 2048);
    line(0, height / 4096, width, height / 4096);
    line(0, height / 8192, width, height / 8192);
    line(0, height / 16384, width, height / 16384);
    line(0, height / 32768, width, height / 32768);
    line(0, height / 65536, width, height / 65536);
    line(0, height / 131072, width, height / 131072);
    line(0, height / 262144, width, height / 262144);
    line(0, height / 524288, width, height / 524288);
    line(0, height / 1048576, width, height / 1048576);
    line(0, height / 2097152, width, height / 2097152);
    line(0, height / 4194304, width, height / 4194304);
    line(0, height / 8388608, width, height / 8388608);
    line(0, height / 16777216, width, height / 16777216);
}

図20

間隔が次第に半分になっていくような漸近する平行線。「アキレスと亀」の寓話のようでもあり、キャンバスの上辺が地平線に見える。

ウォール・ドローイング#106※21

Arcs from the midpoints of two sides of the wall.
(壁の2辺の中点から円弧を描く)

function setup() {
    createCanvas(400, 400);
}
//Arcs from the midpoints of two sides of the wall.
function draw() {
    background(255);
    stroke(0);
    strokeWeight(2);
    line(width / 2, 0, width / 2, height);
    line(0, height / 2, width, height / 2);
    arc(width / 2, height / 2, width / 2, height / 2, 0, PI);
    arc(width / 2, height / 2, width / 2, height / 2, PI, TWO_PI);
    arc(width / 2, height / 2, width / 2, height / 2, PI, PI);
}

図21

指示に沿って、関数 arc() を用いたコードが生成された。線は2本で、円は3つの弧から成っている。

ウォール・ドローイング#358※22

A 12″ (30cm) grid covering the wall. Within each 12″ (30cm) square, one arc from the corner. (The direction of the arcs and their placement are determined by the draftsman.)
(壁を覆う30cmのグリッド。各30cm四方の中に、コーナーから1つずつ円弧を描く。円弧の向きや配置は製図者が決める)

function setup() {
    createCanvas(400, 400);
}
//A 12" (30 cm) grid covering the wall. Within each 12" (30 cm) square, one arc from the corner. (The direction of the arcs and their placement are determined by the draftsman.)
function draw() {
    background(220);
    stroke(0);
    strokeWeight(1);
    for (var x = 0; x < width; x += 30) {
        for (var y = 0; y < height; y += 30) {
             arc(x, y, 30, 30, 0, PI);
             }
        }

図22

30cmは30ピクセルと解釈される。円弧(半円)がキャンバスに敷き詰められる。

次に、リースが提示したソフトウェア構造の(一部)からコードを生成する。

ソフトウェア構造#001※23

Every possible pairing of these sixteen curves: Use the additive numeric values from each curve to set the value of a series of horizontal lines from white to black.
(16本の曲線のありとあらゆる組み合わせ。各曲線の加算値を用いて、白から黒への一連の水平線の値を設定する)

function setup() {
    createCanvas(400, 400);
}
//Every possible pairing of these sixteen curves:Use the additive numeric values from each curve to set the value of a series of horizontal lines from white to black.
function draw() {
    background(255);
    stroke(0);
    strokeWeight(1);
    line(0, 0, width, 0);
    line(0, height / 2, width, height / 2);
    line(0, height, width, height);
    line(width / 2, 0, width / 2, height);
    line(width, 0, width, height);
    line(0, 0, width, height);
    line(0, height / 2, width, 0);
    line(0, height, width, height / 2);
    line(width / 2, 0, width, height);
    line(width, 0, width / 2, height);
    line(0, 0, width / 2, height);
    line(0, height / 2, width / 2, height);
    line(width / 2, 0, width, height / 2);
    line(width, height / 2, width / 2, height);
    line(0, height, width / 2, 0);
    line(width / 2, height, width, height / 2);
    line(width, height, width / 2, 0);
    line(width / 2, height, width, height / 2);
    line(0, 0, width, height);
    line(width, 0, 0, height);
    line(0, height / 2, width, height / 2);
    line(width, height / 2, 0, height);
    line(0, height, width, height);
    line(width, height, 0, height / 2);
    line(0, 0, width, height);
    line(width, 0, 0, height);
    line(0, height / 2, width, height / 2);
    line(width, height / 2, 0, height);
    line(0, height, width, height);
    line(width, height, 0, height / 2);
    line(0, 0, width, height);
    line(width, 0, 0, height);
    line(0, height / 2, width, height / 2);
    line(width, height / 2, 0, height);
    line(0, height, width, height);
    line(width, height, 0, height / 2);
    line(0, 0, width, height);
    line(width, 0, 0, height);
    line(0, height / 2, width, height / 2);
    line(width, height / 2, 0, height);
    line(0, height, width, height);
    line(width, height, 0, height / 2);
}

図23

キャンバスの頂点、あるいは各辺の中点を結ぶ、さまざまな直線を描くコードが生成された。

ソフトウェア構造#002※24

A grid of points in the top half of the surface. Each point moves downward and returns to the top when it leaves the bottom edge. Beginning in the upper-left, each row and column moves faster than the previous. The speeds combine so the point in the upper-left is the slowest and the point in the lower-right is the fastest. Copy and flip the grid across the central vertical axis.
(サーフェスの上半分にある格子状の点。各点は下方に移動し、下端から離れると上部に戻る。左上から始まって、各行、各列は前のものより速く移動する。速度の組み合わせは、左上の点が最も遅く、右下の点が最も速くなるようにする。グリッドをコピーして、中央の縦軸を横切って反転させる)

function setup() {
    createCanvas(400, 400);
}
//A grid of points in the top half of the surface. Each point moves downward and returns to the top when it leaves the bottom edge. Beginning in the upper-left, each row and column moves faster than the previous. The speeds combine so the point in the upper-left is the slowest and the point in the lower-right is the fastest. Copy and flip the grid across the central vertical axis.
function draw() {
    background(255);
    stroke(0);
    strokeWeight(1);
    noFill();
    translate(width / 2, height / 2);
    for (var i = 0; i < width; i += 10) {
        beginShape();
        for (var j = 0; j < height; j += 10) {
            var x = i;
            var y = j;
            var speed = dist(i, j, width / 2, height / 2);
            var angle = map(speed, 0, width, 0, TWO_PI);
            x += cos(angle) * speed;
            y += sin(angle) * speed;
            vertex(x, y);
        }
        endShape();
    }
}

図24

緩やかな弧が、少しずつ変形しながら左から右側へと描かれていく。これまでの実直なまでに逐次的なコードと異なり、繰り返しと変数を用いた、読み甲斐のあるコードである。

ソフトウェア構造#003※25

A surface filled with one hundred medium to small sized circles. Each circle has a different size and direction, but moves at the same slow rate.
Display:
A.The instantaneous intersections of the circles
B.The aggregate intersections of the circles
(100個の中〜小型の円で埋め尽くされた表面。それぞれの円は大きさも向きも違うが、同じ速度でゆっくり動く。A.各円の瞬時の交点、B.円の集合的な交点、を表示しなさい)

この指示からは、複数のコードが生成された。

function setup() {
    createCanvas(400, 400);
}
//A surface filled with one hundred medium to small sized circles. Each circle has a different size and direction, but moves at the same slow rate. Display:
//A.The instantaneous intersections of the circles
//B.The aggregate intersections of the circles
function draw() {
    background(220);
    stroke(0);
    strokeWeight(2);
    noFill();
    for (var i = 0; i < 100; i++) {
        var x = random(width);
        var y = random(height);
        var r = random(10, 20);
        ellipse(x, y, r, r);
    }
    noFill();
    stroke(0, 0, 255);
    strokeWeight(2);
    for (var i = 0; i < 100; i++) {
        var x = random(width);
        var y = random(height);
        var r = random(10, 20);
        ellipse(x, y, r, r);
    }
    noFill();
    stroke(255, 0, 0);
    strokeWeight(2);
    for (var i = 0; i < 100; i++) {
        var x = random(width);
        var y = random(height);
        var r = random(10, 20);
        ellipse(x, y, r, r);
    }
    noFill();
    stroke(0, 255, 0);
    strokeWeight(2);
    for (var i = 0; i < 100; i++) {
        var x = random(width);
        var y = random(height);
        var r = random(10, 20);
        ellipse(x, y, r, r);
    }
    noFill();
    stroke(0, 0, 0);
    strokeWeight(2);
    for (var i = 0; i < 100; i++) {
        var x = random(width);
        var y = random(height);
        var r = random(10, 20);
        ellipse(x, y, r, r);
    }
}

図25

RGB3色と黒の4色の円がランダムに配置される。動きはかなり早く、交点も(見ればわかるが)表示されない。

function setup() {
    createCanvas(400, 400);
}
//A surface filled with one hundred medium to small sized circles. Each circle has a different size and direction, but moves at the same slow rate. Display:
//A.The instantaneous intersections of the circles
//B.The aggregate intersections of the circles
function draw() {
    background(220);
    stroke(0);
    strokeWeight(2);
    noFill();
    for (var i = 0; i < 100; i++) {
        var x = random(width);
        var y = random(height);
        var r = random(10, 20);
        var d = random(1, 5);
        var c = color(random(255), random(255), random(255));
        fill(c);
        ellipse(x, y, r, r);
        ellipse(x + d, y + d, r, r);
        ellipse(x - d, y - d, r, r);
        ellipse(x + d, y - d, r, r);
        ellipse(x - d, y + d, r, r);
    }

図26

ランダムな色による5つの円のクラスタが、ランダムな位置に100個配置される。あまり見たことのないテイストのグラフィック。円の重なりが立体感を感じさせる。

コメントを指示の前半部分(だけ)にすると、このようなコードが生成される。

function setup() {
    createCanvas(400, 400);
}
//A surface filled with one hundred medium to small sized circles. Each circle has a different size and direction, but moves at the same slow rate. Display the instantaneous intersections of the circles.
function draw() {
    background(220);
    stroke(0);
    strokeWeight(1);
    noFill();
    for (var i = 0; i < 100; i++) {
        var x = random(width);
        var y = random(height);
        var r = random(10, 20);
        var d = random(1, 5);
        var a = random(0, 360);
        ellipse(x, y, r, r);
        ellipse(x + d, y + d, r, r);
        ellipse(x + d * 2, y + d * 2, r, r);
        ellipse(x + d * 3, y + d * 3, r, r);
        ellipse(x + d * 4, y + d * 4, r, r);
        ellipse(x + d * 5, y + d * 5, r, r);
        ellipse(x + d * 6, y + d * 6, r, r);
        ellipse(x + d * 7, y + d * 7, r, r);
        ellipse(x + d * 8, y + d * 8, r, r);
        ellipse(x + d * 9, y + d * 9, r, r);
        ellipse(x + d * 10, y + d * 10, r, r);
        ellipse(x + d * 11, y + d * 11, r, r);
        ellipse(x + d * 12, y + d * 12, r, r);
        ellipse(x + d * 13, y + d * 13, r, r);
        ellipse(x + d * 14, y + d * 14, r, r);
        ellipse(x + d * 15, y + d * 15, r, r);
        ellipse(x + d * 16, y + d * 16, r, r);
        ellipse(x + d * 17, y + d * 17, r, r);
        ellipse(x + d * 18, y + d * 18, r, r);
    }
}

図27

単色であるが、さまざまな速度による動きを感じさせる。これも、あまり見たことのないテイストのグラフィックである。

ソル・ルゥイットのウォール・ドローイングが、以下のマサチューセッツ現代美術館(MASS MoCA)のサイトにまとめられている。ここに掲載されているさまざまな指示群は、アンクリエイティブ・コーディングの豊富なリソースである。

SOL LEWITT: A WALL DRAWING RETROSPECTIVE※26

その中から、いくつか試してみたものを、以下に紹介したい。

ウォール・ドローイング#130※27

Grid and arcs from four corners.
(四隅からのグリッドと弧)

function setup() {
    createCanvas(400, 400);
}
//Grid and arcs from four corners.
function draw() {
    background(255);
    stroke(0);
    strokeWeight(1);
    for (var i = 0; i < width; i += 20) {
        line(i, 0, i, height);
    }
    for (var i = 0; i < height; i += 20) {
        line(0, i, width, i);
    }
    strokeWeight(2);
    stroke(0, 0, 255);
    arc(0, 0, 100, 100, 0, PI);
    stroke(255, 0, 0);
    arc(width, 0, 100, 100, 0, PI);
    stroke(0, 255, 0);
    arc(0, height, 100, 100, 0, PI);
    stroke(255, 255, 0);
    arc(width, height, 100, 100, 0, PI);
}

図28

これは、まさにシンプルな指示の通り。

ウォール・ドローイング#340※28

Six-part drawing. The wall is divided horizontally and vertically into six equal parts. 1st part: On red, blue horizontal parallel lines, and in the center, a circle within which are yellow vertical parallel lines; 2nd part: On yellow, red horizontal parallel lines, and in the center, a square within which are blue vertical parallel lines; 3rd part: On blue, yellow horizontal parallel lines, and in the center, a triangle within which are red vertical parallel lines; 4th part: On red, yellow horizontal parallel lines, and in the center, a rectangle within which are blue vertical parallel lines; 5th part: On yellow, blue horizontal parallel lines, and in the center, a trapezoid within which are red vertical parallel lines; 6th part: On blue, red horizontal parallel lines, and in the center, a parallelogram within which are yellow vertical parallel lines. The horizontal lines do not enter the figures.
(6分割の図面。壁面を縦横に6等分する。第1の部分:赤の上に青の水平線、中央に円、その中に黄色の垂直線。第2の部分:黄色と赤色の水平な平行線と、中央の四角形と青色の垂直な平行線。第3の部分:青と黄の水平平行線上に、中央が三角形で、その中に赤の垂直平行線。第4の部分:赤と黄の水平平行線上に、中央で青の垂直平行線が並ぶ長方形。第5の部分:黄色と青の水平平行線上に、中央が台形で、その中に赤の垂直平行線。第6の部分:青地に赤の水平平行線、中央に黄色の垂直平行線を持つ平行四辺形。横線は図の中に含まれない)

function setup() {
    createCanvas(800, 800);
}
//Six-part drawing. The wall is divided horizontally and vertically into six equal parts. 1st part: On red, blue horizontal parallel lines, and in the center, a circle within which are yellow vertical parallel lines; 2nd part: On yellow, red horizontal parallel lines, and in the center, a square within which are blue vertical parallel lines; 3rd part: On blue, yellow horizontal parallel lines, and in the center, a triangle within which are red vertical parallel lines; 4th part: On red, yellow horizontal parallel lines, and in the center, a rectangle within which are blue vertical parallel lines; 5th part: On yellow, blue horizontal parallel lines, and in the center, a trapezoid within which are red vertical parallel lines; 6th part: On blue, red horizontal parallel lines, and in the center, a parallelogram within which are yellow vertical parallel lines. The horizontal lines do not enter the figures.
function draw() {
    background(0);
    stroke(255);
    strokeWeight(4);
    noFill();
    //1st part
    //rectangle
    rect(100, 100, 200, 200);
    //triangle
    triangle(300, 100, 200, 300, 400, 300);
    //ellipse
    ellipse(200, 200, 100, 100);
    //line
    line(0, 0, width, height);
    //point
    point(width/2, height/2);
    //2nd part
    //rectangle
    rect(100, 300, 200, 200);
    //triangle
    triangle(300, 300, 200, 100, 400, 100);
    //ellipse
    ellipse(200, 400, 100, 100);
    //line
    line(0, 0, width, height);
    //point
    point(width/2, height/2);
    //3rd part
    //rectangle
    rect(100, 500, 200, 200);
    //triangle
    triangle(300, 500, 200, 400, 400, 400);
    //ellipse
    //point
    point(width/2, height/2);
    //4th part
    //rectangle
    rect(300, 100, 200, 200);
    //triangle
    triangle(100, 100, 400, 100, 200, 300);
    //ellipse
    ellipse(400, 200, 100, 100);
    //line
    line(0, 0, width, height);
    //point
    point(width/2, height/2);
    //5th part
    //rectangle
    rect(300, 300, 200, 200);
    //triangle
    triangle(100, 300, 400, 300, 200, 100);
    //ellipse
    ellipse(400, 400, 100, 100);
    //line
    line(0, 0, width, height);
    //point
    point(width / 2, height / 2);
    //6th part
    //rectangle
    rect(300, 500, 200, 200);
    //triangle
    triangle(100, 500, 400, 500, 200, 400);
    //ellipse
    ellipse(400, 600, 100, 100);
    //line
    line(0, 0, width, height);
    //point
    point(width / 2, height / 2);
}

図29

長大な指示。キャンバスを倍の広さに拡張した。色は考慮されなかったが、6つの正方形をベースにした、不思議な線画が構成されている。コードには細かくコメントが入っている。

ウォール・ドローイング#391※29

Two-part drawing. The two walls are each divided horizontally and vertically into four equal parts. First wall: 12-inch (30cm) bands of lines in four directions, one direction in each part, drawn in black India ink. Second wall: Same, but with four colors drawn in India ink and color ink washes.
(2分割の図面。2枚の壁面をそれぞれ縦横に4等分する。第一の壁面:30cmの帯状の線を4方向、各パート1方向ずつ、黒の墨汁で描く。第二の壁面:同じものを、墨汁とカラーインクの4色で描く)

function setup() {
    createCanvas(400, 400);
}
//Two-part drawing. The two walls are each divided horizontally and vertically into four equal parts. First wall: 12-inch (30 cm) bands of lines in four directions, one direction in each part, drawn in black India ink. Second wall: Same, but with four colors drawn in India ink and color ink washes.
function draw() {
    background(255);
    stroke(0);
    strokeWeight(1);
    line(0, 0, width, height);
    line(0, height, width, 0);
    stroke(0, 0, 0);
    strokeWeight(2);
    line(0, 0, width / 4, height / 4);
    line(0, height / 4, width / 4, 0);
    line(width / 4, 0, width / 2, height / 4);
    line(width / 4, height / 4, width / 2, 0);
    line(width / 2, 0, width / 4 * 3, height / 4);
    line(width / 2, height / 4, width / 4 * 3, 0);
    line(width / 4 * 3, 0, width, height / 4);
    line(width / 4 * 3, height / 4, width, 0);
    stroke(0, 0, 0);
    strokeWeight(1);
    line(0, 0, width / 4, height / 4);
    line(0, height / 4, width / 4, 0);
    line(width / 4, 0, width / 2, height / 4);
    line(width / 4, height / 4, width / 2, 0);
    line(width / 2, 0, width / 4 * 3, height / 4);
    line(width / 2, height / 4, width / 4 * 3, 0);
    line(width / 4 * 3, 0, width, height / 4);
    line(width / 4 * 3, height / 4, width, 0);
    stroke(0, 0, 0);
    strokeWeight(1);
    line(0, 0, width / 4, height / 4);
    line(0, height / 4, width / 4, 0);
    line(width / 4, 0, width / 2, height / 4);
    line(width / 4, height / 4, width / 2, 0);
    line(width / 2, 0, width / 4 * 3, height / 4);
    line(width / 2, height / 4, width / 4 * 3, 0);
    line(width / 4 * 3, 0, width, height / 4);
    line(width / 4 * 3, height / 4, width, 0);
}

図30

これも色は表現されていないが、キャンバスに2つの(4等分された)線画が重ねられている。コードの後半は、同じ記述が3回繰り返されている(冗長だが発展性がある?)。

ウォール・ドローイング#415D※30

Double Drawing. Right: Isometric Figure (Cube) with progressively darker graduations of gray on each of three planes; Left: Isometric figure with red, yellow, and blue superimposed progressively on each of the three planes. The background is gray.
(ダブルドローイング。右:3つの平面のそれぞれにグレーを徐々に濃くしたアイソメトリック図形(立方体)。左:3つの平面のそれぞれに赤、黄、青を徐々に重ねたアイソメトリック図形。背景はグレー)

function setup() {
    createCanvas(400, 400, WEBGL);
}
//Double Drawing. Right: Isometric Figure (Cube) with progressively darker graduations of gray on each of three planes; Left: Isometric figure with red, yellow, and blue superimposed progressively on each of the three planes. The background is gray.
function draw() {
    background(220);
    //Right
    push();
    translate(width / 2, height / 2);
    rotateX(frameCount * 0.01);
    rotateY(frameCount * 0.01);
    rotateZ(frameCount * 0.01);
    box(100);
    pop();
    //Left
    push();
    translate(-width / 2, height / 2);
    rotateX(frameCount * 0.01);
    rotateY(frameCount * 0.01);
    rotateZ(frameCount * 0.01);
    box(100);
    pop();
}

図31

キャンバスの右下と左下で、3Dのキューブがゆっくりと回転し続ける。生成されたコードをそのまま実行しようとするとエラーが出たので、createCanvas() の引数に WEBGL を追加した。

ウォール・ドローイング#579※31

Three concentric arches. The outside one is blue; the middle red; and the inside one is yellow.
(3つの同心円状のアーチ。外側は青、真ん中は赤、内側は黄色)

function setup() {
    createCanvas(400, 400);
}
//Three concentric arches. The outside one is blue; the middle red; and the inside one is yellow.
function draw() {
    background(255);
    stroke(0);
    strokeWeight(4);
    noFill();
    arc(200, 200, 300, 300, 0, PI);
    arc(200, 200, 280, 280, 0, PI);
    arc(200, 200, 260, 260, 0, PI);
    fill(255, 0, 0);
    arc(200, 200, 240, 240, 0, PI);
    fill(0, 0, 255);
    arc(200, 200, 220, 220, 0, PI);
    fill(255, 255, 0);
    arc(200, 200, 200, 200, 0, PI);
}

図32

同心円のアーチ(半円)と配色が、指示通りに描かれている。

ウォール・ドローイング#630※32

A wall is divided horizontally into two equal parts. Top: alternating horizontal black and white 8-inch (20cm) bands. Bottom: alternating vertical black and white 8-inch (20cm) bands.
(壁を水平に2等分する。上:黒と白の8インチ(20cm)の帯を水平に交互に並べる。下:黒と白の8インチ(20cm)の帯を交互に縦に並べる)

function setup() {
    createCanvas(400, 400);
}
//A wall is divided horizontally into two equal parts. Top: alternating horizontal black and white 8-inch (20 cm) bands. Bottom: alternating vertical black and white 8-inch (20 cm) bands.
function draw() {
    background(220);
    stroke(0);
    strokeWeight(1);
    line(0, 200, 400, 200);
    line(200, 0, 200, 400);
    for (var i = 0; i < 20; i++) {
        if (i % 2 == 0) {
            fill(0);
        }
        else {
            fill(255);
        }
        rect(0, i * 20, 200, 20);
    }
    for (var i = 0; i < 20; i++) {
        if (i % 2 == 0) {
            fill(0);
        }
        else {
            fill(255);
        }
        rect(i * 20, 0, 20, 200);
    }
}

図33

上下が逆だが、座標の大きい方が上だと考えればこの配置で正しい(#579のアーチの向きも同様)。

ウォールドローイング#631※33

A wall is divided into two equal parts by a line drawn from corner to corner. Left: alternating diagonal black and white 8-inch (20cm) bands from the lower left. Right: alternating diagonal black and white 8-inch (20cm) bands from the upper right.
(角から角へ引いた線で壁を2等分する。左:左下から黒と白の8インチ(20cm)の帯を斜めに交互に配置。右:右上から黒と白の8インチ(20cm)の帯を交互に斜めに配置)

function setup() {
    createCanvas(400, 400);
}
//A wall is divided into two equal parts by a line drawn from corner to corner. Left: alternating diagonal black and white 8-inch (20 cm) bands from the lower left. Right: alternating diagonal black and white 8-inch (20 cm) bands from the upper right.
function draw() {
    background(220);
    stroke(0);
    strokeWeight(1);
    line(0, height / 2, width, height / 2);
    line(width / 2, 0, width / 2, height);
    strokeWeight(8);
    for (var i = 0; i < width / 2; i += 20) {
        line(i, height / 2, i + 10, height / 2 - 10);
        line(i, height / 2, i + 10, height / 2 + 10);
    }
    for (var i = width / 2; i < width; i += 20) {
        line(i, height / 2, i + 10, height / 2 - 10);
        line(i, height / 2, i + 10, height / 2 + 10);
    }
}

図34

指示とは異なるが、あながち間違っているともいえない、妙な感覚のドローイング。

ウォール・ドローイング#793A※34

Irregular wavy color bands.(不規則な波状のカラーバンド)

function setup() {
    createCanvas(400, 400);
}
//Irregular wavy color bands.
function draw() {
    background(0);
    stroke(255);
    noFill();
    beginShape();
    for (var x = 0; x < width; x++) {
        var y = map(noise(x * 0.01, frameCount * 0.01), 0, 1, 0, height);
        vertex(x, y);
    }
    endShape();
}

図35

ランダムな曲線がうねうねと動き続けるアニメーション(なので、コードを実行してみて欲しい)。

ウォール・ドローイング#852※35

A wall divided from the upper left to the lower right by a curvy line; left: glossy yellow; right: glossy purple.
(左上から右下に曲線で仕切られた壁。左:光沢のある黄色、右:光沢のある紫)

function setup() {
    createCanvas(400, 400);
}
//A wall divided from the upper left to the lower right by a curvy line; left: glossy yellow; right: glossy purple.
function draw() {
    background(255);
    stroke(0);
    strokeWeight(2);
    line(0, 0, width, height);
    line(width, 0, 0, height);
    noFill();
    stroke(255, 255, 0);
    strokeWeight(4);
    bezier(width / 2, 0, width / 2, height, width, height, 0, height / 2);
    stroke(255, 0, 255);
    strokeWeight(4);
    bezier(0, height / 2, width, height / 2, width, 0, 0, 0);
}

図36

ベジェ関数を用いた、2本の味わいある曲線。

ウォール・ドローイング#901※36

Color bands and black blob. The wall is divided vertically into six equal bands; red; yellow; blue; orange; purple; green. In the center is a black glossy blob.
(カラーバンドと黒いしみ。壁面は縦に赤、黄、青、オレンジ、紫、緑の6つの帯に分かれている。中央には、黒い光沢のしみがある)

function setup() {
    createCanvas(400, 400);
}
//Color bands and black blob. The wall is divided vertically into six equal bands; red; yellow; blue; orange; purple; green. In the center is a black glossy blob.
function draw() {
    background(255);
    stroke(0);
    strokeWeight(1);
    fill(255);
    rect(0, 0, width, height);
    fill(0);
    ellipse(width / 2, height / 2, width / 2, height / 2);
    fill(255, 0, 0);
    rect(0, 0, width / 2, height / 6);
    fill(255, 255, 0);
    rect(0, height / 6, width / 2, height / 6);
    fill(0, 0, 255);
    rect(0, height / 3, width / 2, height / 6);
    fill(255, 165, 0);
    rect(0, height / 2, width / 2, height / 6);
    fill(0, 0, 0);
    rect(0, height / 1.5, width / 2, height / 6);
    fill(0, 0, 0);
    rect(0, height / 1.2, width / 2, height / 6);
    fill(0, 0, 0);
    rect(0, height / 1, width / 2, height / 6);
    fill(0, 0, 0);
    rect(0, height / 0.8, width / 2, height / 6);
    fill(0, 0, 0);
    rect(0, height / 0.6, width / 2, height / 6);
    fill(0, 0, 0);
    rect(0, height / 0.4, width / 2, height / 6);
    fill(0, 0, 0);
    rect(0, height / 0.2, width / 2, height / 6);
    fill(0, 0, 0);
    rect(0, 0, width / 2, height / 6);
}

図37

不思議な配色と配置の色面構成のように見える。

ウォール・ドローイング#1180※37

Within a four-meter (160″) circle, draw 10,000 black straight lines and 10,000 black not straight lines. All lines are randomly spaced and equally distributed.
4メートル(160インチ)の円の中に、黒い直線を10,000本、直線でない線を10,000本引きます。すべての線はランダムに配置され、均等に分布している)

function setup() {
    createCanvas(400, 400);
}
//Within a four-meter (160") circle, draw 10,000 black straight lines and 10,000 black not straight lines. All lines are randomly spaced and equally distributed.
function draw() {
    background(220);
    stroke(0);
    strokeWeight(1);
    for (var i = 0; i < 10000; i++) {
        var x = random(width);
        var y = random(height);
        var d = dist(x, y, width / 2, height / 2);
        if (d < 160) {
            line(x, y, x, y);
        }
    }
}

図38

半径160ピクセルの円内に、10000本のランダムな線が生成されるアニメーション。ただし、線の始点と終点が同じ座標であるため、線ではなく点に見える。