#05 ビジュアルコーディングを始めよう

ワンライナーの世界へ

いよいよ最終回です。これまで学んだ四角形・ループ・三角関数・アニメーションのすべてを凝縮して、数行〜1行で動く視覚アートを作ります。

「ワンライナービジュアルコーディング」は、 デモシーン? 小さなファイルサイズ・少ないコードで驚くほどの映像や音楽を作るプログラマーのサブカルチャー。「ワンライナーコーディング」はこの文化から生まれた。 の文化から生まれた遊びです。「できるだけ短いコードで、できるだけかっこいいものを作る」という挑戦です。


圧縮のテクニック

まず、コードを短くする基本テクニックを整理します。

変数宣言をまとめる

// 長い書き方
var x = W / 2;
var y = H / 2;
var r = 100;

// 短い書き方
var x = W/2, y = H/2, r = 100;

セミコロンとカンマで1行にまとめる

// 普通の書き方(4行)
ctx.fillStyle = '#0d1117';
ctx.fillRect(0, 0, W, H);
ctx.fillStyle = '#00e5ff';
ctx.fillRect(50, 50, 100, 100);

// 圧縮(1行)
ctx.fillStyle='#0d1117',ctx.fillRect(0,0,W,H),ctx.fillStyle='#00e5ff',ctx.fillRect(50,50,100,100);

カンマ演算子 , で複数の式を繋ぐことができます。

ビット演算でフロア除算

Math.floor(x)  // 小数点以下切り捨て(通常)
x | 0          // ビットOR 0(同じ結果・短い)
~~x            // 二重ビット否定(同じ結果)

for ループの圧縮

// 普通
for (var i = 0; i < 100; i++) { ... }

// 圧縮
for (var i = 0; i < 100; i++) ...  // ブロックが1文なら {} を省略
for (var i = 100; i--;) ...        // カウントダウン・i が 0 になるまで

即時実行関数式(IIFE)

// 名前付き関数 + 呼び出し
function draw() { ... }
draw();

// IIFE(即時実行)
!function draw() { ...; requestAnimationFrame(draw); }();

!function(function で始める書き方で、定義と同時に実行できます。


作品集 ① — カラーグリッドのワンライナー

まず読みやすいバージョンを確認します。

// 読みやすいバージョン(6行)
var size = 30;
for (var x = 0; x < W; x += size) {
  for (var y = 0; y < H; y += size) {
    ctx.fillStyle = 'hsl(' + ((x + y) * 0.5) + ', 80%, 55%)';
    ctx.fillRect(x, y, size - 1, size - 1);
  }
}

これをワンライナーに圧縮すると:

for(var s=30,x=0;x<W;x+=s)for(var y=0;y<H;y+=s)ctx.fillStyle='hsl('+(x+y)*.5+',80%,55%)',ctx.fillRect(x,y,s-1,s-1);
カラーグリッド(ワンライナー版)
for(var s=30,x=0;x<W;x+=s)for(var y=0;y<H;y+=s)ctx.fillStyle='hsl('+(x+y)*.5+',80%,55%)',ctx.fillRect(x,y,s-1,s-1);

作品集 ② — コンパクトなローズ曲線

読みやすいバージョン:

// 読みやすいバージョン(8行)
ctx.fillStyle = '#0d1117';
ctx.fillRect(0, 0, W, H);
ctx.beginPath();
var n = 7;
for (var i = 0; i <= 720; i++) {
  var a = i * Math.PI / 180;
  var r = 110 * Math.cos(n * a);
  var x = W/2 + r * Math.cos(a);
  var y = H/2 + r * Math.sin(a);
  i === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y);
}
ctx.strokeStyle = '#ff6b9d';
ctx.lineWidth = 1.5;
ctx.stroke();

圧縮版(3行):

ctx.fillStyle='#0d1117',ctx.fillRect(0,0,W,H),ctx.beginPath();
for(var n=7,i=0;i<=720;i++){var a=i*Math.PI/180,r=110*Math.cos(n*a);ctx[i?'lineTo':'moveTo'](W/2+r*Math.cos(a),H/2+r*Math.sin(a));}
ctx.strokeStyle='#ff6b9d',ctx.lineWidth=1.5,ctx.stroke();
ローズ曲線 n=7(圧縮版・3行)
ctx.fillStyle='#0d1117',ctx.fillRect(0,0,W,H),ctx.beginPath();
for(var n=7,i=0;i<=720;i++){var a=i*Math.PI/180,r=110*Math.cos(n*a);ctx[i?'lineTo':'moveTo'](W/2+r*Math.cos(a),H/2+r*Math.sin(a));}
ctx.strokeStyle='#ff6b9d',ctx.lineWidth=1.5,ctx.stroke();

作品集 ③ — アニメーション渦

時間変数 t を使ったアニメーションも圧縮できます。

var t=0;!function f(){
  ctx.fillStyle='rgba(13,17,23,.12)',ctx.fillRect(0,0,W,H);
  for(var i=0;i<20;i++){
    ctx.beginPath();
    ctx.arc(W/2+Math.cos(t+i*.5)*i*6,H/2+Math.sin(t+i*.5)*i*6,3,0,7);
    ctx.fillStyle='hsl('+(t*50+i*18)+',90%,60%)';
    ctx.fill();
  }
  t+=.03,requestAnimationFrame(f);
}();
渦巻きアニメーション(圧縮版)
var t=0;!function f(){
ctx.fillStyle='rgba(13,17,23,.12)',ctx.fillRect(0,0,W,H);
for(var i=0;i<20;i++){
  ctx.beginPath();
  ctx.arc(W/2+Math.cos(t+i*.5)*i*6,H/2+Math.sin(t+i*.5)*i*6,3,0,7);
  ctx.fillStyle='hsl('+(t*50+i*18)+',90%,60%)';
  ctx.fill();
}
t+=.03,requestAnimationFrame(f);
}();

作品集 ④ — ピクセルアート(数式で絵を描く)

キャンバスの各ピクセルの色を数式で決めると、純粋に数学から生まれる絵が描けます。

for (var y = 0; y < H; y++) {
  for (var x = 0; x < W; x++) {
    var v = Math.sin(x * 0.04) * Math.cos(y * 0.04) * Math.sin((x - y) * 0.03);
    ctx.fillStyle = 'hsl(' + (v * 180 + 200) + ',80%,' + (v * 30 + 50) + '%)';
    ctx.fillRect(x, y, 1, 1);
  }
}
数式から生まれる干渉縞
for(var y=0;y<H;y++)for(var x=0;x<W;x++){var v=Math.sin(x*.04)*Math.cos(y*.04)*Math.sin((x-y)*.03);ctx.fillStyle='hsl('+(v*180+200)+',80%,'+(v*30+50)+'%)';ctx.fillRect(x,y,1,1);}

作品集 ⑤ — スターフィールド

ランダムな星が流れるクラシックなデモシーン表現です。

スターフィールド — 奥から手前に飛んでくる星
ctx.fillStyle='#0d1117';ctx.fillRect(0,0,W,H);
var stars=[];
for(var i=0;i<200;i++)stars.push({x:Math.random()*W,y:Math.random()*H,z:Math.random()*W,pz:0});
!function f(){
ctx.fillStyle='rgba(13,17,23,0.25)';ctx.fillRect(0,0,W,H);
stars.forEach(function(s){
  s.pz=s.z;
  s.z-=4;
  if(s.z<=0)s.z=W,s.x=Math.random()*W,s.y=Math.random()*H;
  var sx=((s.x-W/2)/s.z)*W+W/2;
  var sy=((s.y-H/2)/s.z)*W+H/2;
  var px=((s.x-W/2)/s.pz)*W+W/2;
  var py=((s.y-H/2)/s.pz)*W+H/2;
  var r=Math.max(0,(1-s.z/W)*3);
  ctx.beginPath();ctx.moveTo(px,py);ctx.lineTo(sx,sy);
  ctx.strokeStyle='rgba(255,255,255,'+(1-s.z/W)+')';
  ctx.lineWidth=r;ctx.stroke();
});
requestAnimationFrame(f);
}();

よく使うスニペット集

背景クリア(完全)

ctx.fillStyle = '#0d1117'; ctx.fillRect(0, 0, W, H);

背景クリア(残像あり)

ctx.fillStyle = 'rgba(13,17,23,0.15)'; ctx.fillRect(0, 0, W, H);

円を描く

ctx.beginPath(); ctx.arc(x, y, r, 0, 7); ctx.fill();

Math.PI * 2 ≈ 6.28 なので 7 で代用できます(ちょっと超えるだけで問題なし)。

全ピクセルループ

for (var y = 0; y < H; y++) for (var x = 0; x < W; x++) { ... }

ランダムな角度

Math.random() * Math.PI * 2

インデックスから色相

'hsl(' + (i * step) + ',80%,60%)'

アニメーション骨格

var t=0; !function f(){ /* 描画 */ t+=.03; requestAnimationFrame(f); }();

次のステップ

このシリーズで学んだことは入り口に過ぎません。さらに深く探求したい方へ:

挑戦してみること

  • n の値を変えてローズ曲線の形を変える
  • 色式を変えて好みのパレットを作る
  • パーティクルに重力(vy += 0.1)を追加する
  • 2つのスパイラルをずらして重ねる

参考になるコミュニティ

  • p5.js — Canvasをさらに使いやすくするライブラリ。スケッチを書いて共有できる
  • The Coding Train — アルゴリズムとビジュアルコーディングの動画チャンネル
  • twigl.app — ツイート300文字以内でWebGLシェーダーを書いて競う場

シリーズのまとめ

このシリーズで学んだこと:

内容
#01 Canvas要素? HTMLの`<canvas>`要素は、JavaScriptで2D/3Dグラフィックスを描画するための画面領域。ピクセル単位で自由に描画でき、ゲームやビジュアルアートに使われる。 描画コンテキスト? canvasに描画するための命令セット。`canvas.getContext("2d")`で取得し、`ctx.fillRect()`や`ctx.arc()`などのメソッドで図形を描く。 座標系? Canvas上の位置を(x, y)の数値ペアで表す仕組み。左上が原点(0,0)でxは右向き、yは下向きに増加する(数学の座標系とy軸が逆)。 HSL? 色相(Hue 0〜360)・彩度(Saturation)・明度(Lightness)で色を指定する方式。ループ変数から色相を計算しやすく、ビジュアルコーディングで多用される。
#02ループ・グリッド・Math.sin() のパターン
#03arc() ラジアン? 角度の単位。円一周が2π(約6.28)ラジアン。`Math.sin()`や`Math.cos()`はラジアンを受け取る。度数法との変換は「ラジアン = 度数 × π / 180」。 パラメトリック曲線? パラメーターtを変化させてx=f(t), y=g(t)で点の軌跡を描く方法。ローズ曲線・リサジュー曲線など複雑な形状を少ない式で表現できる。 ・ローズ曲線
#04 requestAnimationFrame? ブラウザの画面更新タイミング(通常1秒60回)に合わせて関数を繰り返し呼ぶAPI。アニメーションの標準実装方法で、`setInterval`より滑らかで省電力。 ・時刻変数・残像・パーティクル
#05コード圧縮・作品例・ デモシーン? 小さなファイルサイズ・少ないコードで驚くほどの映像や音楽を作るプログラマーのサブカルチャー。「ワンライナーコーディング」はこの文化から生まれた。 的思考

「コードは短い。でも絵は複雑」——これがビジュアルコーディングの魔法です。ループ・三角関数・時間、この3つの組み合わせだけで無限の表現が生まれます。

ぜひ数式を変えながら、自分だけのビジュアルを作ってみてください。