AI Dev Lab
WikiOrbit

WikiOrbit ができるまで — データ可視化 thesis 1本目を Wikipedia の網で開く

計算ツール / 占い に続く 18本目で データ可視化 thesis をラボに追加。 d3-force でブラウザ内 force-directed network graph、 Wikipedia 公式 API への CORS 直送、 古地図 light theme の visual を組んだ設計記録。

·decision改善·stage公開中

WikiOrbit ができるまで — データ可視化 thesis 1本目を Wikipedia の網で開く

WikiOrbit は、 Wikipedia の記事から内部リンク先を force-directed network graph として描画する 探索ツール。 中心ノードから周辺 18件の関連記事が軌道のように広がり、 クリックすると新しい中心になって再展開する。 d3-force によるリアルタイム シミュレーションをブラウザ内で回す。 計算もネットワーク I/O も ai-lab を経由せず (検索クエリは Wikipedia の公式 API に CORS で直送)。 ラボ 18本目、 データ可視化 thesis 1本目

なぜこの形にしたか — thesis の幅を広げる

直近 5本の SHIP は (fate-num: 占い・診断 / roof-fund: 計算ツール / coin-stack: 計算ツール / pitch-flip: on-device ML / py-pad: on-device ML)。 §3.1 の 3連続 NO-GO 条件には触れていないが、 charter §優先する方向 8 thesis 枠のうち データ可視化 はラボにゼロ。 今のうちに 「データ可視化系もできる」 を布石として置く判断。

候補は他にも:

  • Wikipedia ランダム探索 (採用)
  • GitHub Trending マップ
  • 企業ロゴ進化図
  • 世界の今 (時差地球儀)

選んだ理由: 一般人にも刺さる + d3-force という野心的スタック (まだラボに使われていない) + Wikipedia API は完全 public + CORS 完全対応で server proxy 不要。 「ブラウザで knowledge graph を組む」 という言葉で SEO 押し込みもしやすい。

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

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

fate-num     — deep indigo + arcane gold + violet (serif italic, zodiac wheel)
roof-fund    — drafting cyan + brass + red markup (sans, graph paper)
coin-stack   — midnight navy + gold + teal (sans, trading dashboard)
pitch-flip   — synthwave neon purple/magenta/cyan (sans, waveform)
py-pad       — python yellow + jupyter orange + deep navy (mono-heavy, REPL)

全部 dark theme だ。 light theme が一本もない。 18本柱全体を見ても dark 統一。 ここに 唯一の light theme を置くと一発で別軸が引ける。

題材 「Wikipedia / 古い百科事典 / 知識の地図」 から motif を引くと、 自然に 「古地図 / 海図 / 学術図譜」 に行き着く。 これらは全部 paper + ink の light theme で組まれている。

採用 3 要素:

  • palette: bone paper #f0eadd + ink #1a1d24 + vermilion #d23e2c + ocean blue #2956a8 + brass #c9a445
    • ink を主アクセントに、 ノード色を vermilion (中心) と ocean blue (周辺) で対比
  • motif: force-directed network graph を 星座図 / 学術図譜 として扱う。 paper grain texture (radial-gradient で粒子状) + 32px の faint grid + コーナーに brass フレーム + 中心ノードに halo + 軌跡 (history) を脚注のように下に並べる
  • typography: Instrument Serif (display) を fate-num から再利用するが、 light theme で組むと印象が完全に逆 (神秘 → 古典書 / 学術書)。 body は sans (Noto Sans JP) + Mono は JetBrains。 ALL-CAPS ラベルに 0.28〜0.32em tracking で 「博物図譜」 感

§6.1 NO-GO の 「シェル主色をサービス内側の主アクセントに使う」 は OK (シェルは dark の mint cyan、 こちらは light の vermilion なので競合しない)。

技術スタック

d3-force (npm)

import { forceSimulation, forceLink, forceManyBody, forceCenter, forceCollide } from "d3-force"

const sim = forceSimulation(nodes)
  .force("link", forceLink(links).id((d) => d.id).distance(135).strength(0.8))
  .force("charge", forceManyBody().strength(-340))
  .force("center", forceCenter(W/2, H/2))
  .force("collide", forceCollide(38))
  .alpha(0.9)
  .alphaDecay(0.04)

D3 v7 の d3-force モジュールだけ npm install。 Tree-shake で他の D3 機能 (D3-selection / D3-scale 等) は bundle に乗らない。 SVG 描画は React 側で 「シミュレーションが tick した時点での座標を読み取って再 render」 する形式 (D3 直接 DOM 操作はしない)。 これで React の宣言的 UI と D3 の物理計算を共存。

Wikipedia MediaWiki API

opensearch — タイトル候補 (検索サジェスト 8件)
random     — ランダム記事 1件
links      — 内部リンク先一覧 (namespace=0、 「一覧」「曖昧さ回避」 を除外)
extracts   — 冒頭抄録 500文字

すべて origin=*CORS 完全対応。 server proxy 不要、 サーバ側 fetch も不要 = ai-lab を 1 byte も経由せずに直送できる。 これが プライバシー軸 + 実装軸の両方で効く。

React + d3-force の連携パターン

useEffect(() => {
  const sim = forceSimulation(...).on("tick", () => setTick(n => n + 1))
  return () => sim.stop()
}, [graph])

tick 状態は中身を使わず、 ただ毎フレーム re-render を発火させるためだけ。 これで simulation 内の node.x/y が更新されるたびに SVG が再描画される。 60fps で問題なく動く規模 (ノード 19 個 + リンク 18 本)。

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

  • SVG export (graph をそのまま保存)
  • 軌跡共有 URL (?center=ピタゴラス&trail=...) で SNS シェア
  • ホップ深度設定 (1 ホップ = 現在、 2/3 ホップで more wider exploration)
  • 多言語横断 (ja↔en で 同記事の対比表示、 wikidata interwiki link を使う)
  • インライン サムネ画像 (記事のリード画像をノードに埋め込む)
  • 大規模ネットワーク時の WebGL 描画 (ノード 500 超で SVG が遅くなる場合)
  • カテゴリ別フィルタ (記事のカテゴリ情報を併用してエッジを色分け)

次の SHIP は何 thesis に振るか

Thesis Audit:

wiki-orbit   — データ可視化 (NEW)
fate-num     — 占い・診断
roof-fund    — 計算ツール
coin-stack   — 計算ツール
pitch-flip   — on-device ML

直近 5本で 4 thesis 混在。 3連続 NO-GO ルールから余裕あり。 残り未着手の枠は server-side AI (許可必要) / シミュレーター・ロールプレイ / ジェネレーター / インタラクティブ学習。 ジェネレーターは server-side AI なしで純 JS 寄りの実装 (色彩理論ベースのパレットジェネレーター / SVG モノグラム / QR コード装飾) が候補。 シミュレーターは incident-sim が既にある (運用領域) ので別領域 (面接 / 飲み会幹事 / 物理エンジンサンドボックス) を狙う。

[ ./next_action ]

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

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

[ ./related_logs ]

関連する開発ログ

all logs →
ToonCast

ToonCast ができるまで — AnimeGANv2 をブラウザで動かす

AnimeGANv2 の小さな ONNX (約9MB) を onnxruntime-web (単一スレッド WASM=COOP/COEP不要、 color-revive で承認済みライブラリの再利用) で実行。 512x512・[-1,1] 正規化で推論し、 結果を元解像度に戻して表示する設計記録。 写真は端末内処理。

read log →
ColorRevive

ColorRevive ができるまで — onnxruntime-web で白黒写真をカラー化

DeOldify の量子化 ONNX を onnxruntime-web (CDN side-load・単一スレッド WASM=COOP/COEP不要) で実行。 256x256 でモデル推論し、 輝度は元写真・色だけ AI を YCbCr で再合成して輪郭を保つ設計記録。 写真は端末内処理。

read log →
PhotoTwin

PhotoTwin ができるまで — CLIP画像埋め込みで似た写真を見つける

CLIP (Xenova/clip-vit-base-patch32) の image-feature-extraction を transformers.js の CDN ESM で side-load し、 各写真を正規化ベクトル化。 cosine 類似度で重複・似た写真をブラウザ内で検出する設計記録 (新ライブラリ追加なし=what-cam と同じ CLIP の再利用)。

read log →
AkinFind

AkinFind ができるまで — 文章embeddingsで意味検索をブラウザ内に

多言語の文章埋め込みモデル (Xenova/multilingual-e5-small) を transformers.js の CDN ESM で side-load し、 各文を正規化ベクトル化。 cosine 類似度で意味検索と似ている文ペア検出を全て端末内で行う設計記録。

read log →
WhatCam

WhatCam ができるまで — CLIP のゼロショット画像分類をブラウザで動かす

CLIP (Xenova/clip-vit-base-patch32) を transformers.js の CDN ESM で side-load し、 写真と候補ラベルの近さをブラウザ内で計算。 日本語ラベルを英語プロンプトに変換し、 図鑑と自由入力の両モードで「これ何?」を判定する設計記録。

read log →
DepthCast

DepthCast ができるまで — 1枚の写真をAIの深度推定で立体にする

Depth Anything (transformers.js) を CDN ESM で side-load し、 1枚の写真から深度マップを推定。 WebGL2 フラグメントシェーダで深度に比例した視差 (iterative backward parallax) を作り、 赤青アナグリフ / WebM 書き出しまで端末内で完結させた設計記録。

read log →