わずか数kbの小さいプログラムですごい映像を実現するプログラム「メガデモ」、MSX-FANでの1画面プログラムなどの文化を継いだ、Twitterのツイート内に収まるプログラムが熱い!
「
たった256文字のJavaScriptコードで描かれた街の風景アニメがスゴ過ぎて訳がわからない - やじうまの杜 - 窓の杜」
このツイート内の256文字のコードをindex.htmlとして保存して、ブラウザで開き、クリックすると実際に動き出します!
改行もなく詰め込んだプログラムを解いて、解析してみます。
まずは、インデントを付けて、読みやすく
<canvas style=width:99% id=c>
<script type="module">
let t, w, i, a, b, s, X, d, Z, Y;
const f = () => {
for (
c.width = w = 99,
++t,
i = 6e3;
i--;
c.getContext`2d`.fillRect(i % w, i / w | 0, 1 - d * Z / w + s, 1)
) {
for (
a = i % w / 50 - 1,
s = b = 1 - i / 4e3,
X = t,
Y = Z = d = 1;
++Z < w & (
Y < 6 - (32 < Z & 27 < X % w && X / 9 ^ Z / 8) * 8 % 46 || d |
(
s = (X & Y & Z) % 3 / Z,
a = b = 1,
d = Z / w
)
);
Y -= b
) {
X += a
}
}
};
setInterval(f, t = 99);
</script>
次にfor文内に詰め込まれたプログラム。実行順序を確認。(src on GitHub)
let i = 0;
for (alert(1), alert(2); alert(3), alert(4), i < 3; alert(5), i++) {
alert("loop")
}
これに準じて(正確にはちょっと違うけど)展開して、コメントを入れてみました。
let t; // フレーム数
const f = () => {
let w;
c.width = w = 99;
++t;
let s; // 背景
let d;
let Z; // X座標
for (let i = w * 60 + 1; i--;) {
const color = 1 - d * Z / w + s; // オリジナル
//const color = s; // s のみでもそれなりに
//const color = 1 - d * Z / w; // 背景なし
//const color = d * Z / w; // 背景なし、反転
//const color = d * Z / w + s; // 背景あり、反転
//const color = d * Z / w; // 背景なし、反転
c.getContext("2d").fillRect(i % w, i / w | 0, color, 1)
let a = i % w / 50 - 1; // ビルの横幅 50 を小さくすると細くなる
let b;
s = b = 1 - i / 4000; // 背景
let X = t; // フレーム数tに連動する、描画初期位置
let Y;
Y = Z = d = 1;
for (; ++Z < w; Y -= b) {
X += a;
//if (Y < 6 - (32 < Z & 27 < X % w && X / 9 ^ Z / 8) * 8 % 46) {
//if (Y < 6 - (((32 < Z) & (27 < X % w)) && (X / 9) ^ (Z / 8)) * 8 % 30) {
//const xo = (X / 9) ^ (Z / 8);
//const xo = Z / 3; // 奥行き方向の形 三角
//const xo = X / 3; // 横方向の形 三角
const xo = 3 & (Z / 5);
const n = 32 < Z && 10 < X % 20 && xo; // 横座標20の内10だけ表示
//const n = (32 < Z) & (27 < X % w) && xo;
//const n = (80 < Z) && xo; // 表示距離 80より遠方
//const n = (80 < Z) & (27 < X % w) && xo; // 表示距離 80より遠方、横幅wの内27までを表示
if (Y < 6 - n * 8) {
// if (Y < 6) { // 地平線のみ
continue;
}
//s = (X & Y & Z) % 3 / Z; // オリジナル 格子
//s = (Y & Z) % 3 / Z, // 横線
//s = (X & Z) % 3 / Z, // 縦線
//s = (X & Y) % 3 / Z, // ぐちゃぐちゃ
s = 1 / Z; // グラデーションのみ
a = b = 1;
d = Z / w;
break;
}
}
};
setInterval(f, t = 1000 / 60);
6e3 は、6000 と等価で1文字短くなります
(一番下の行が中途半端なのは6000がキャンバス幅99で割り切れないため)
c.getContext("2d") を c.getContext`2d` と書くことで2文字短縮。
| 0 とビット演算を使うことで、Math.floor の代わりに。
fillRectで、少数を使って塗ることで、白から黒へのグラデーションを実現。
(X / 9) ^ (Z / 8) この数式が、ビルを表現。
(X & Y & Z) % 3 / Z この数式で、窓を表現。
シンプルにしてみたものがこちら。
「city」(src on GitHub)
コンピューターが非力なMSX時代によく見た、簡易3D表現、いまでもなかなかオシャレです。