# Natural Motion Lab 自然の動きを、ひとつずつ。 小さなルールから生まれる動きを触って探し、Webページへ持ち帰る実験集です。 LPの背景、フェスの余白、ブランドの小さな動きに使うことを目指します。 [公開された実験室を開く](https://natural-motion-lab.shoseilab.com/) ## 今ある作品 | 作品 | しくみ | 触れるところ | | --- | --- | --- | | 香りの流れ | Curl noise | 風、渦、広がり、寿命。ポインターでも流れを曲げられます | | 渦の庭 | Curl noiseと回転する流れ | うねり、回転、細かさ、速さ、尾が残る時間、先端の太さ | | 火の粉 | Curl noiseと上昇・慣性 | 横風、上昇、乱れ、寿命、粒の数、粒の大きさ、炎の長さ | | 水中の光 | Curl noiseで揺れる光の帯 | 揺らぎ、光の向き、広がり、深さ、速さ | | 育つ模様 | Gray–Scott反応拡散 | feed、kill、速さ。クリックで種を追加できます | | 光の道 | 粘菌から着想した粒子モデル | 探索距離、旋回、痕跡の減衰、速度。道を描けます | | 呼吸する光 | Swarmalators | 集まり方、同期の強さ、呼吸の速さ | 各作品に見本、シード、設定リンク、埋め込みコードがあります。 「流れの実験」では、香り・渦・火の粉・水中の光を切り替えられます。 最初の渦のデモを広げた「渦の庭」から始め、見本の「ひとつの大きな渦」も試せます。 リンクが保存するのは初期設定です。途中の模様、操作履歴、一時停止状態は保存しません。 同じ設定とシードなら同じ初期状態から始まりますが、異なる計算方式や端末間の画像の完全一致は保証しません。 ## 起動する Bunがあれば、外部パッケージのインストールなしで動かせます。 ```sh cd natural-motion-lab bun scripts/dev.mjs ``` [ローカルの実験室](http://127.0.0.1:4178/) を開きます。終了はターミナルで `Ctrl+C`。 サーバーはこの端末のループバックだけで待ち受けます。ローカルURLは他の人の端末からは開けません。 `just` がある場合は、次のコマンドも使えます。 | コマンド | 内容 | | --- | --- | | `just dev` | 編集中のサイトを表示 | | `just check` | 数値計算・設定の検証とMarkdownチェック | | `just wasm` | MoonBitからWasmを再生成 | | `just bench` | 同じ反応拡散をJavaScript / Wasmで計測 | | `just build` | 検証後、公開用の `dist/` を生成 | | `just preview` | `dist/` をローカルで表示 | `dev` と `preview` は同じポートを使います。切り替えるときは先に動いている方を終了してください。 `check` / `build` には `rumdl`、Wasmの再生成にはMoonBitが必要です。 確認環境はBun 1.4.2、moon 0.1.20260915、moonc v0.10.13+cbb11c36fです。 生成済みの `assets/reaction.wasm` を同梱しているので、閲覧と通常のビルドにMoonBitは不要です。 MoonBitのソースを変更した場合は `just wasm` → `just check` → `just build` の順で再生成します。 ## ページへ組み込む `src/` と `assets/` を、組み込み先の `natural-motion/` ディレクトリにコピーします。 次の例は、装飾用のキャンバスと停止操作だけを置きます。 ```html ``` 動く完成例は [examples/landing.html](examples/landing.html) にあります。 `file://` で直接開かず、HTTPサーバーで配信してください。 ES Modules、Canvas 2D、ResizeObserver、IntersectionObserverを使う現行ブラウザー向けです。 - `effect`: `flow` / `vortex` / `embers` / `underwater` / `reaction` / `physarum` / `swarm` - `seed`: 0〜4294967295の整数 - `params`: 各作品の調整値。範囲と既定値は [src/catalog.js](src/catalog.js) - `engine`: 反応拡散のみ `auto` / `js` / `moon`。Wasmが読めない場合はJavaScriptへ切り替わります - `interactive: true`: キャンバス上の操作を有効化。装飾用途では既定の `false` を使います - `paused`: 初期停止状態。省略するとOSの「視差効果を減らす」設定に従います 返り値の `setParams({...})`、`setPaused(true)`、`destroy()` で外側から操作できます。 別の種類やシードに変える際は `destroy()` 後に作り直します。 画面外・別タブでは計算を止め、OSの動きを減らす設定にも応答します。 作品ごとにキャンバスと計算状態が独立しています。 ## 静的サイトとして共有する `just build` の出力 `dist/` を静的ホスティングへ配置できます。 GitHub Pagesなどのサブディレクトリ配信を想定し、アセットは相対パスです。 ブラウザー以外の実行環境、APIサーバー、外部CDNは不要です。 JavaScriptを適切なMIME型で配信し、可能なら `.wasm` を `application/wasm` に設定します。 この実装はWasmをArrayBufferから読み込むため、WasmのMIME型だけで失敗しません。 ソースはGitButlerで管理し、GitHubの `t-edzuka/natural-motion-lab` 非公開リポジトリで共有します。 サイトはCloudflare Workers Static Assetsで公開する構成です。 ブラウザーで実行するJavaScriptとWasmは配信されます。GitHubを非公開にしても、配信されたコードは閲覧できます。 自作コードは [MIT License](LICENSE) とし、再利用できる形にしています。 配信にはプロジェクト内で固定したWranglerを使います。 ```sh bun install --frozen-lockfile --ignore-scripts bun run deploy:check bun run deploy ``` GitHub ActionsはPRで検証し、`main` の更新時に検証後デプロイします。 自動デプロイはproduction環境のSecret登録後、 リポジトリ変数 `DEPLOY_ENABLED=true` で有効にします。 認証と運用手順はリポジトリ内の `docs/deployment.md` に記録します。この文書はサイトへ配信しません。 ## 実装の方針 画面は標準HTML / CSS / JavaScript、計算が重い反応拡散だけMoonBitのWasmを試しています。 同じモデルのJavaScript版を残し、比較とフォールバックに使います。 MoonBitは固定長の線形メモリーと少数の数値関数だけを公開し、言語固有のオブジェクト表現を渡しません。 描画・数値計算に外部ライブラリは使っていません。配信ツールのWranglerだけを開発依存として固定しています。 火の粉と水中の光は写真の形・明暗を参考にした演出です。速度は実物の動画との照合前です。 次は気に入った作品を一つ選び、実物の動画を観察して、形・速度・消え方を磨く予定です。 炎、風に揺れる草、水面の干渉波も候補です。 粒子数や解像度を上げて限界が見えたら、Zig / Rustの比較やWebGL / WebGPUを検討します。 数学的な前提、言語の選び方、検証結果は [調査と制作ノート](docs/research.md) にまとめています。