p5.jsの公式リファレンスを見ていたら、p5.jsの作品を動画として出力するならばCCapture.jsとかを使えばいいよって書いてありました試してみたところ、ちょっとだけはまったのでまとめておきます。
必要なものは、CCapture.jsとgif.jsです(それとp5.jsも)。
CCpature.jsは/build/CCapture.all.min.js
が、gif.jsは/dist/gif.worker.js
が使用するファイルとなります。
このうちのCCapture.all.min.js
だけをスクリプトタグで読み込んでおきます。
<script src="./js/CCapture.all.min.js"></script>
gif.worker.js
はCCapture.all.min.js
がスクリプト内で動的に読み込み処理を行うので、スクリプトタグで読み込んでおく必要はありません。
このときに同一オリジンポリシーを回避するために、htmlファイルが置いてある場所で以下のようにローカルサーバーを立ち上げておきます(これ以外方法でローカルサーバーを立ち上げてももちろん大丈夫です)。
$ python -m SimpleHTTPServer
http://localhost:8000/
にアクセスするとhtmlファイルを開くことができます。
CCapture.jsでは以下のような操作により、gifアニメを作成することができます。
// in initialization phase
var capturer = new CCapture({format: 'gif', workersPath: './js/', verbose: true});
capturer.start();
// in rendering loop
captuerer.capture(canvas);
// to finish recording
capturer.stop();
capturer.save();
CCaptuerクラスのコンストラクタに渡すオブジェクトのうちworkersPath
はgif.worker.js
が置いてあるディレクトリへのパスを指定するものです。
verbose
オプションは必ずしも必要ではありませんが、あるとコンソールに処理の進捗が出力されるので、進行具合がわかりやすくなります。
CCapture#capture
メソッドの引数にはcanvas要素を渡します。
p5.js
のcreateCanvas
でcanvasを作成した場合、canvas要素は以下の方法で取得できます。
var p5Canvas = createCanvas(500, 500);
var canvas = canvas.canvas;
(p5.jsの公式リファレンスにはcreateCanvas
の返り値はHTMLCanvasElement
と書かれていますが、実際にはp5.Renderer2D
クラスのオブジェクトが返り値になっています)
実際にp5.jsでCCapture.jsを使用したソースコードは以下のようになります。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Sample to making anmation gif for p5.js by CCapture.js</title>
</head>
<body>
<script src="./js/p5.js"></script>
<script src="./js/CCapture.all.min.js"></script>
<script>
var loopFrame = 180;
var capturer = new CCapture({format: 'gif', workersPath: './js/', verbose: true});
var canvas;
function setup() {
var p5Canvas = createCanvas(500, 500);
canvas = p5Canvas.canvas;
rectMode(CENTER);
noStroke();
colorMode(HSB, 360, 100, 100);
capturer.start();
}
function draw() {
background(0);
var t = (frameCount % loopFrame) / loopFrame;
for (var w = 0; w <= width; w += 20) {
for (var h = 0; h <= height; h += 20) {
var d = sqrt(sq(w - width / 2) + sq(h - height / 2));
var size = lerp(5, 10, sin(d * 0.1 + t * TWO_PI * 2.0) * 0.5 + 0.5);
fill(t * 360, 100, 100);
rect(w, h, size, size);
}
}
if (frameCount < loopFrame) {
capturer.capture(canvas);
} else if (frameCount === loopFrame) {
capturer.stop();
capturer.save();
}
}
</script>
</body>
</html>