#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() のパターン |
| #03 | arc()・ ラジアン? 角度の単位。円一周が2π(約6.28)ラジアン。`Math.sin()`や`Math.cos()`はラジアンを受け取る。度数法との変換は「ラジアン = 度数 × π / 180」。 ・ パラメトリック曲線? パラメーターtを変化させてx=f(t), y=g(t)で点の軌跡を描く方法。ローズ曲線・リサジュー曲線など複雑な形状を少ない式で表現できる。 ・ローズ曲線 |
| #04 | requestAnimationFrame? ブラウザの画面更新タイミング(通常1秒60回)に合わせて関数を繰り返し呼ぶAPI。アニメーションの標準実装方法で、`setInterval`より滑らかで省電力。 ・時刻変数・残像・パーティクル |
| #05 | コード圧縮・作品例・ デモシーン? 小さなファイルサイズ・少ないコードで驚くほどの映像や音楽を作るプログラマーのサブカルチャー。「ワンライナーコーディング」はこの文化から生まれた。 的思考 |
「コードは短い。でも絵は複雑」——これがビジュアルコーディングの魔法です。ループ・三角関数・時間、この3つの組み合わせだけで無限の表現が生まれます。
ぜひ数式を変えながら、自分だけのビジュアルを作ってみてください。