ai-lab.org
FracCast

FracCast ができるまで — シミュレーター 3本目を WebGL2 フラクタル で開く

ジェネレーター 3本目 (patch-pad) に続く ラボ 30本目で シミュレーター thesis 3本目 (pile-park / doodle-drop に続く)。 WebGL2 fragment shader で escape-time iteration を GPU per-pixel 並列実行、 17世紀 数学者ノートブック motif (ivory + sepia + brass + crimson) で組んだ設計記録。

·decision改善·stage公開中

FracCast ができるまで — シミュレーター 3本目を WebGL2 フラクタル で開く

FracCast は、 WebGL2 fragment shader で動く ブラウザ マンデルブロ + Julia 集合 エクスプローラー。 ラボ 30本目、 シミュレーター thesis 3本目 (PilePark 物理 / DoodleDrop お絵描き物理 に続く、 数学イテレーション動力学のシミュレーション)。

なぜこの形にしたか

直近 5本 (patch-pad / doodle-drop / side-tax / atlas-quest / hue-deck) にシミュレーターは doodle-drop の 1本のみ、 連続にならず §3.1 OK。

候補比較:

  • フラクタル エクスプローラー (採用) — WebGL2 shader が wow、 SEO 中程度
  • 反応拡散 (Gray-Scott) — wow 強だが SEO ニッチ
  • Conway ライフゲーム — 安全だが wow 中
  • 計算ツール 5本目 育休給付金 — SEO 強だが wow 薄い

選んだ理由:

  • WebGL2 fragment shader 直書き という野心的スタック (Three.js を使わず raw GL)
  • GPU 並列計算 = 「ピクセル 1 個 = 1 つの複素点」 で 60fps 実時間 zoom
  • 既存大手 (XaoS / Mandelbulber) はデスクトップアプリ or 重い WebGL、 「ブラウザでサクッと」 路線で差別化
  • 教育コンテンツ需要 (大学 数学 / プログラミング授業) が継続的
  • type-forge / astro-cast (Three.js 3D) との 対比軸 = 「2D 数学を raw shader で」

visual direction — §6.1 Visual Audit 15本目の適用

直近 5本の visual を書き出す:

patch-pad    — walnut wood + cream panel + brass + chrome (70s モジュラー シンセ)
doodle-drop  — blackboard green + chalk pastels (学校黒板)
side-tax     — ledger green + paper cream + stamp red (帳簿事務所)
atlas-quest  — dark navy + amber LED departure (空港 board)
hue-deck     — warm gray + lipstick + chrome (Pantone)

題材 「フラクタル / マンデルブロ / 数学」 → motif 候補:

  • 17世紀 数学者ノートブック (ivory paper + sepia ink + brass corner + crimson margin) ← 採用
  • 80s シンセウェーブ neon フラクタル (pitch-flip と被る)
  • 顕微鏡 観察 (bioluminescent green/cyan)
  • 黒板 + 白チョーク (doodle-drop と緑被る)
  • 大理石 古代神殿 (重すぎ)

採用 3 要素:

  • palette: warm ivory paper #f4ead4 + ink #1a1812 + sepia #6a4a28 + crimson margin #b22e1f + brass corner #c9a04e + sage seal #4a6b3d + fractal own palette per shader (6 種)
    • light theme 4本目 (hue-deck / wiki-orbit / pile-park に続く) だが motif で完全別
  • motif: 17世紀 数学者ノートブック (graph paper 23px 罫線 + 数式 inscriptions μ-Mandelbrot / ζ-Julia + brass corner 4 隅 + crimson margin + dashed border の手書きノート感)
  • typography: Space Grotesk 800 (math display) + Instrument Serif italic (数式 / subtitle) + JetBrains Mono (coordinate / iter readout)

技術スタック

WebGL2 raw setup (no Three.js)

const gl = canvas.getContext("webgl2", { antialias: false })
if (!gl) throw new Error("WebGL2 not supported")

const vs = compile(gl.VERTEX_SHADER, VERT_SRC)
const fs = compile(gl.FRAGMENT_SHADER, FRAG_SRC)
const prog = gl.createProgram()
gl.attachShader(prog, vs); gl.attachShader(prog, fs); gl.linkProgram(prog)

Three.js を使わずに raw WebGL2 を直書き。 全画面 quad 1 枚に fragment shader を実行するだけなので、 数百 KB の Three.js を読み込む価値がない (= type-forge / astro-cast との対比 = 「2D 数学は raw GL で軽量に」)。

Escape-time iteration in GLSL ES 3.00

#version 300 es
precision highp float;

uniform vec2 u_center;
uniform float u_zoom;
uniform vec2 u_aspect;
uniform int u_maxIter;

void main() {
  vec2 uv = (v_uv - 0.5) * 2.0 * u_aspect;
  vec2 c = u_center + uv * u_zoom;
  vec2 z = vec2(0.0);
  float zr = z.x, zi = z.y;
  float zr2 = zr * zr, zi2 = zi * zi;

  int iter = 0;
  const int MAX_LOOP = 4096;
  for (int i = 0; i < MAX_LOOP; i++) {
    if (i >= u_maxIter) break;
    if (zr2 + zi2 > 256.0) break;  // 発散判定 (|z|² > 256)
    float zri = zr * zi;
    zr = zr2 - zi2 + c.x;
    zi = 2.0 * zri + c.y;
    zr2 = zr * zr; zi2 = zi * zi;
    iter++;
  }
  // ...
}

WebGL2 (GLSL ES 3.00) では for 文の上限定数を要求するので、 ループ上限 MAX_LOOP=4096 をコンパイル時定数で確保し、 ランタイムの u_maxIter で内側で break。 escape 半径は |z|² > 256 (= 16²)、 これは smooth coloring の対数項を安定化させる古典的選択。

Smooth coloring (log-log normalize)

float modz = sqrt(zr2 + zi2);
float mu = float(iter) + 1.0 - log2(log2(modz));
float t = log(1.0 + mu) / log(1.0 + float(u_maxIter));

iter をそのまま色付けすると等高線状の縞 (bands) が出る。 smooth coloring の mu = iter + 1 - log2(log2(|z|)) で連続値を出すと縞が消えて滑らかなグラデーションになる。 さらに深い zoom でも階調が見えるように、 t = log(1+mu) / log(1+maxIter) で対数マッピング。

Pan / Zoom 維持 (mouse-anchored zoom)

function zoomAt(xPx: number, yPx: number, factor: number) {
  const before = pxToComplex(xPx, yPx)
  params.zoom *= factor
  const after = pxToComplex(xPx, yPx)
  params.centerX += before.x - after.x
  params.centerY += before.y - after.y
}

マウス位置の complex 座標 を zoom 前後で固定にする古典実装。 「マウス下の点が画面上で動かない」 と感じる UX を実現。 Pan は setPointerCapture + delta 累積。

Julia c アニメ

function tick(now: number) {
  if (params.animateJulia && params.mode === "julia") {
    const t = now * 0.0006
    params.juliaCx = 0.7885 * Math.cos(t)
    params.juliaCy = 0.7885 * Math.sin(t)
    dirty = true
  }
  if (dirty) render()
  requestAnimationFrame(tick)
}

c がマンデルブロ集合の境界をなぞるように 0.7885 半径の円を周回 (古典的演出)、 Julia 集合の形が連続変態 (morph) する。

やっていない / これからの IMPROVE

  • double-double 浮動小数演算 で 10^14 を超える深い zoom (現状は単精度 GPU で 10^7 が実用限界)
  • WebGL2 不在環境向け WebGL1 fallback + JavaScript fallback (CPU 描画でも 200x200 grid なら ~5 fps で動く)
  • PNG エクスポート (canvas.toBlob で 1920x1200 高解像度書き出し)
  • 共有 URL で 中心座標 + zoom + iter + palette を base64 シリアライズ → リンク共有
  • bookmark 機能 で localStorage に お気に入り座標保存
  • Burning Ship フラクタル 等の z² + c 以外の漸化式 (絶対値変種など)
  • 3D Mandelbulb / Quaternion Julia (ray-marched fragment shader)
  • WebGL 拡張: GL_ARB_gpu_shader_fp64 (倍精度 GPU) — 一部ハードウェアのみ
  • GPGPU 解析 (escape time の分布をヒストグラム出力 / Pseudo-coloring の彩色アルゴリズム拡張)

次の SHIP は何 thesis に振るか

Thesis Audit:

frac-cast    — シミュレーター (3本目)
patch-pad    — ジェネレーター (3本目)
doodle-drop  — シミュレーター (2本目)
side-tax     — 計算ツール (4本目)
atlas-quest  — 学習 (2本目)

直近 5本で シミュレーター が 2 つ (frac-cast / doodle-drop)、 ジェネレーター 1 つ (patch-pad)、 計算 1 つ、 学習 1 つ。 §3.1 連続 3 NO-GO に近づくため次は別 thesis 優先:

  • 計算ツール 5本目 (育休給付金 / 退職金 / 国保 / 年金)
  • 占い 3本目 (MBTI / 命名占い / 血液型 / 動物占い)
  • データ可視化 3本目 (企業ロゴ進化 / GitHub Trending / 都道府県 GDP)
  • 学習 3本目 (タイピング / 暗算 / 漢字検定 / 都道府県クイズ)
  • 8 thesis 残り 1 枠 = server-side AI (ユーザー許可待ち)

[ ./next_action ]

読んだら、 FracCast を実際に動かす。

この開発ログは FracCast をどう作ったかの記録です。 読み終わったらそのままサービス本体へ戻って、 実物で価値を確かめてください。

[ ./related_logs ]

関連する開発ログ

all logs →
PatchPad

PatchPad ができるまで — ジェネレーター 3本目を ブラウザ モジュラー シンセ で開く

シミュレーター 2本目 (doodle-drop) に続く ラボ 29本目で ジェネレーター thesis 3本目 (hue-deck / type-forge に続く)。 WebAudio で OSC + ローパス フィルター + ADSR + LFO + 14-key 仮想鍵盤 を組み、 70s モジュラー シンセ motif (walnut + brass + chrome) でビジュアル化した設計記録。

read log →
DoodleDrop

DoodleDrop ができるまで — シミュレーター 2本目を お絵描き物理 で開く

計算ツール 4本目 (side-tax) に続く ラボ 28本目で シミュレーター thesis 2本目 (pile-park に続く)。 matter.js + Canvas + 凸包 (Andrew's monotone chain) でストロークを polygon body 化、 黒板 motif の visual を組んだ設計記録。

read log →
SideTax

SideTax ができるまで — マネー計算機 4本目を 副業税金 で開く

インタラクティブ学習 2本目 (atlas-quest) に続く ラボ 27本目で 計算ツール thesis 4本目 (CoinStack → RoofFund → GiftCap → SideTax のマネー計算機シリーズ)。 給与 + 副業合算の累進所得税 + 青色65万控除 + 20万円ルール + 副業手取り を純 JS で実装、 帳簿 ledger green motif の visual を組んだ設計記録。

read log →
AtlasQuest

AtlasQuest ができるまで — インタラクティブ学習 2本目を 国旗クイズ + 世界地図で

ジェネレーター 2本目 (hue-deck) に続く ラボ 26本目で インタラクティブ学習 thesis 2本目 (tone-quest に続く)。 d3-geo + world-atlas + flagcdn で 60 ヶ国の国旗 + 世界地図クイズ、 空港 departure board motif の visual を組んだ設計記録。

read log →
HueDeck

HueDeck ができるまで — ジェネレーター 2本目を chroma-js で配色パレット

データ可視化 2本目 (astro-cast) に続く ラボ 25本目で ジェネレーター thesis 2本目 (type-forge に続く)。 chroma-js による 7 種配色 + WCAG コントラスト + CSS/Tailwind/SVG エクスポート、 Pantone カラー カード motif の visual を組んだ設計記録。

read log →
AstroCast

AstroCast ができるまで — データ可視化 2本目を 太陽系 3D で開く

占い 2本目 (arcana-flip) に続く ラボ 24本目で データ可視化 thesis 2本目 (wiki-orbit に続く)。 Three.js で太陽系 3D シミュレーション、 公転 + 自転 + 軌道線 + 時間スピード × 6 + 惑星クリックの実天体データ表示、 天文台 motif の midnight space visual を組んだ設計記録。

read log →