- バウハウスの基礎理論である「極性の対比(形態・色彩のコントラスト)」をプログラミングの視点で読み解く
- フックの法則(バネ運動)と包絡線の数理を用いて、混沌から秩序へ収束する動的なアルゴリズムを構築する
- 1600×900のキャンバス描画と、
sキーでの画像保存機能を備えたp5.jsの実装コードを理解する
どうもクリエイティブコーダーのワタタクです。
こちらの記事『【バウハウスってなに?】ものづくりとアートをひとつにして、毎日の暮らしを便利で美しく変えた学校』では、「バウハウス」という言葉の意味や思想について言語化しました。 感覚まかせに「描く」のではなく、機能とルールから「設計する」というバウハウスの考え方は、僕たちが普段取り組んでいるクリエイティブコーディングそのものです。
今回はその実践編として、バウハウスの予備課程で教えられていた「対比(コントラスト)の理論」を、p5.jsの物理シミュレーションと幾何学アルゴリズムに翻訳していきます。無秩序な点が、バネの力学によって美しい幾何学模様(包絡線)へと整列していく過程を一緒にコードで組んでみましょう。
この記事を書いた人


クリエイティブコーダー
「才能」ではなく「発見」で描く。文系・36歳からの上達ログ。
- ゼロから独学でクリエイティブコーディングに挑戦し、以下の実績を達成
- 開始1年8ヶ月目までに公募6つに挑戦し、3つ入選(勝率50%)
- KITTE大阪の18メートルあるAxCROSS大型スクリーン
- 虎ノ門ヒルズステーションタワーB2F TOKYO NODE エントランスサイネージで展示
- UN:O(東京大手町)にある会員限定のサテライトオフィスにて2作品選出・常設展示
- 開始1年8ヶ月目までに公募6つに挑戦し、3つ入選(勝率50%)
- 開始1年9ヶ月目に、虎ノ門ヒルズ49階、地上250mのインフィニティプールへ作品提供・展示
造形と数理への翻訳
視覚的イメージと造形秩序(イッテン的形態・色彩の対比)
ヨハネス・イッテンがバウハウスの予備課程で説いた造形の根源は、「極性の対比(コントラスト)」にあります。
- 幾何学形態の対比:静止した完全なる正方形(大地・安定・重厚)と、無限の回転と張力を孕む真円(精神・流動・運動)。この2つの形態が画面上で近接するとき、両者の隙間に強烈な視覚的テンションが発生します。
- 色彩のコントラスト:冷徹なウルトラマリン(寒色・後退・沈黙)と、熱量を放つカドミウムオレンジ(暖色・進出・覚醒)。ただ二色を置くのではなく、面積比と明度差を厳密に計算することで、画面全体が呼吸するかのような脈動を作り出します。
「デザインする」とは、これらの対比要素をただ並べることではありません。画面の中央に配置された幾何学が、周囲の余白(ネガティブスペース)と緊張感のある対話を交わしている状態を、数学的・幾何学的な厳密さをもって確立することです。
コード・物理挙動への落とし込み(バネ運動・境界線の数理)
デジタルな画面におけるデザインは、静止画ではなく「時間と物理法則」を伴います。無秩序な粒子(混沌)が、マウスの接近や時間の経過によって、イッテン的な厳密な幾何学パターン(秩序)へと収束していくプロセスを数理モデルで構築します。
- 調和振動(Spring Physics):フックの法則(F = -kx – cv)を用い、秩序ある目標座標(Target)へ向かって各点が有機的な粘性と弾力性を持って収束する運動をシミュレートします。無機質な線形補間(Linear)ではなく、バネの減衰運動を介することで、造形に「生命的な張力」が宿ります。
- 包絡線とパラメトリック曲線:円の円周上の点を等間隔に配置し、各点から特定のルール(倍数写像:i → (i × k) mod n)に基づいて直線(弦)を引くことで、カルディオイドやネフロイドといった美しい包絡線を動的に生成します。
- ノイズによる微細な揺らぎ(Perlin Noise):完全な数学的秩序の中に、ごくわずかなパーリンノイズを付加します。これにより、機械的な冷徹さを脱し、人間の手描きのストロークが持つ「微細な不揃いの美」をコードで再現します。
実装プロトタイプ(コードと解説)
以下のコードは、p5.jsを用いて「混沌(ランダムな粒子)が、相互作用によってイッテン的秩序(数理的な幾何学包絡線)へと収束するデザインの生成過程」をミニマルに表現した完全なプロトタイプです。
キャンバスサイズは 1600×900 に固定しており、マウスを動かすと空間に引力場が発生し、無秩序だった点と線がバネの力学に従って端正な数理曲線(カージオイド的包絡線)へと整列します。また、p5.jsのWeb editorで実行された表現をクリックして、キーボードの s(またはS)キーを押すと、その瞬間のキャンバスがPNG画像としてPC(デフォルトのダウンロード先/デスクトップ等)に保存されます。


/**
* Prototype: The Genesis of Design
* 混沌から秩序への収束:調和振動子による幾何学包絡線の生成
* キャンバスサイズ: 1600 x 900
* 操作: マウス移動で秩序への収束と係数変化 / 's'キーでPNG保存
*/
const NUM_POINTS = 120;
let points = [];
let targetRadius;
let multiplier = 2; // 包絡線を決定する係数
function setup() {
// 1600×900の固定サイズでキャンバスを生成
createCanvas(1600, 900);
colorMode(RGB, 255);
smooth();
targetRadius = min(width, height) * 0.35;
// 初期化:すべての点を画面内のランダムな位置(混沌)に配置
for (let i = 0; i < NUM_POINTS; i++) {
points.push(new Node(random(width), random(height), i));
}
}
function draw() {
// 純黒ではなく、深い思索を思わせるニュートラルダークグレー
background(18, 18, 20, 40);
translate(width / 2, height / 2);
// マウスのX位置によって包絡線の規則性(係数)を滑らかに変化させる
let targetMultiplier = map(mouseX, 0, width, 2, 6, true);
multiplier += (targetMultiplier - multiplier) * 0.05;
// 各ノードの目標位置(円周上の均等配置)を更新し、物理更新
for (let i = 0; i < NUM_POINTS; i++) {
let angle = map(i, 0, NUM_POINTS, 0, TWO_PI);
let tx = cos(angle) * targetRadius;
let ty = sin(angle) * targetRadius;
// マウスが中央に近いほど、外乱(ノイズ)が抑えられ完全な幾何学へ収束する
let distFromCenter = dist(mouseX - width / 2, mouseY - height / 2, 0, 0);
let noiseFactor = map(distFromCenter, 0, width / 2, 0, 80, true);
tx += (noise(i * 0.1, frameCount * 0.01) - 0.5) * noiseFactor;
ty += (noise(i * 0.1 + 100, frameCount * 0.01) - 0.5) * noiseFactor;
points[i].setTarget(tx, ty);
points[i].update();
}
// 構造線の描画(イッテン的対比:冷たい青灰色のベース構造)
stroke(100, 140, 180, 25);
strokeWeight(0.75);
noFill();
for (let i = 0; i < NUM_POINTS; i++) {
let targetIndex = floor((i * multiplier) % NUM_POINTS);
line(points[i].pos.x, points[i].pos.y, points[targetIndex].pos.x, points[targetIndex].pos.y);
}
// ノード(点)の描画:幾何学の境界を告げる極小の光
noStroke();
for (let i = 0; i < NUM_POINTS; i++) {
// 接触点における微細な暖色アクセント
if (i % 6 === 0) {
fill(255, 120, 60, 200); // カドミウムオレンジの残光
ellipse(points[i].pos.x, points[i].pos.y, 3, 3);
} else {
fill(220, 225, 230, 160);
ellipse(points[i].pos.x, points[i].pos.y, 1.5, 1.5);
}
}
}
// 物理的なバネ振動を担うクラス
class Node {
constructor(x, y, index) {
this.pos = createVector(x, y);
this.vel = createVector(0, 0);
this.acc = createVector(0, 0);
this.target = createVector(x, y);
this.index = index;
// 物理パラメータ
this.k = 0.04; // バネ定数(弾性)
this.damp = 0.85; // 減衰率(粘性)
}
setTarget(tx, ty) {
this.target.set(tx, ty);
}
update() {
let force = p5.Vector.sub(this.target, this.pos);
force.mult(this.k);
this.acc.add(force);
this.vel.add(this.acc);
this.vel.mult(this.damp);
this.pos.add(this.vel);
this.acc.mult(0); // 加速度のリセット
}
}
// 's' または 'S' キーが押されたら画像を保存する
function keyPressed() {
if (key === 's' || key === 'S') {
saveCanvas('bauhaus_genesis_' + frameCount, 'png');
}
}(※ブラウザのセキュリティ仕様上、p5.jsの saveCanvas() はブラウザ設定の「ダウンロード先フォルダ」に保存されます。デスクトップに直接保存したい場合は、ブラウザのダウンロード保存先をデスクトップに設定してお使いください。)
パラメータ調整の要点
this.k(バネ剛性)とthis.damp(減衰係数):kを低く(0.02程度)、dampを高め(0.88程度)に設定することで、冷たい機械的なスナップではなく、ゼリーや上質な紙のように「ゆったりと空気抵抗を受けて収束する」高級感のあるイージングが生まれます。- 線のアルファ値(透明度):
stroke(100, 140, 180, 25)のように、極めて低い不透明度(約10%)で数十本の線を重ねることで、線と線が交差する結節点だけに自然な光の密度(濃度差)が生まれ、コードによるボリューメトリックな陰影が立ち上がります。
まとめ
今回は、バウハウスの「極性の対比」というデザイン理論を、p5.jsのバネ運動と包絡線のアルゴリズムに落とし込みました。 ただランダムに図形を動かすのではなく、「どんな物理法則と色彩のルールを与えれば、画面に緊張感と調和が生まれるか?」と設計するプロセスは、まさに現代のデジタル・バウハウスといえます。
ぜひ this.k や NUM_POINTS の数値を書き換えて、自分だけの「秩序が立ち現れる瞬間」を s キーで切り取ってみてください。
それでは今日もレッツワクワクコーディング。

