# くるり。ソフトクリームシミュレーター

> ボタンを押すだけで、どう遊んでもきれいなソフトクリームが巻ける3Dゲーム。フレーバーを切り替えてミックスを作り、回して眺めて、結果を画像で残せる。

- 制作: [ワカメ](https://wakame.dev/)（個人で企画・開発）
- ステータス: 公開中
- 制作期間: 2026-10
- カテゴリ: Web, Game, Graphics
- 使用技術: WebGL2, GLSL, JavaScript (ES Modules), Web Audio API
- 担当: 企画, クリームの物理計算, シェーダー実装, ゲーム設計・採点, 公開

## 概要

3Dライブラリを使わず、WebGL2とGLSLで直接描いたソフトクリームの3Dシミュレーションゲームです。クリームは1本の連続した帯として計算していて、ノズルから出て重力で落ち、コーンに積もります。落ちたクリームは必ず理想のらせんの位置に収まり、コーンも自動で回るので、どう遊んでもきれいにしか巻けません。最初のひと巻きは平らな土台になり、そこから1巻きごとに1本分ずつ高くなって、目標の量でぴたっと止まり先端がつんと仕上がります。クリームの管はGPUで組み立てていて、CPUは断面ごとの位置と向きだけを渡し、星型の絞り口による6本の筋は頂点シェーダーで作っています。量とフレーバーが決まった5種類のオーダーがあり、途中でフレーバーを切り替えてミックスを作れます。完成後は作業台を回して眺め、結果カードを画像で保存・シェアできます。

## クリームを1本の帯として計算する

ノズルから出たクリームは、一定量ごとの小さな節として追加し、隣どうしを伸び縮みできるひもでつないでいます。重力で落ち、コーンのふち・積み上がったクリーム・皿にぶつかって止まります。節ごとに別々の玉として扱うと細いらせんが座屈してしまうため、同じ帯の近い部分どうしは押し合わないようにしています。

ソフトクリームはある程度の力までは形を保つ性質（降伏応力）があるので、支えられた部分は「コーンからの相対位置」を覚えて、ばねのようにコーンについていきます。コーンを急に動かしたり、ふちからはみ出すほど外側にしぼったりすると、このつながりが切れて垂れ落ちます。

## 見た目は計算結果をなめらかにして作る

描画では、計算した節の位置を少しだけ平滑化してから曲線で補間し、その周りに断面を並べた管を毎フレーム作り直しています。断面は円ではなく、星型の絞り口を通ったときの6本の筋を持つ形です。ずり落ちたり途中で切れたりした帯は、離れた部分どうしを勝手につながないようにしています。

しぼるのを止めたときや仕上げのときは、最後の十数節をだんだん細くして、ソフトクリームらしい「つん」とした先端を作ります。

## Three.jsからWebGL2へ書き直した

最初はThree.jsで作っていましたが、3Dライブラリを使わずWebGL2とGLSLで直接描く形に書き直しました。物理計算と採点はそのままで、描画だけを置き換えています。

いちばん大きな変更はクリームの管です。以前はCPUで毎フレーム、最大1600断面×48頂点の位置・法線・色を計算して送り直していました。今はCPUが断面ごとの中心・太さ・向き（平行移動させた法線と従法線）・色だけを浮動小数点テクスチャに書き込み、頂点シェーダーが gl_VertexID から断面の頂点と法線を計算します。つながった区間は断面2枚ぶんの三角形ストリップをインスタンス描画し、別の帯との切れ目はクリップ範囲の外へ追い出して描かないようにしています。

ワッフルコーンの格子は、以前は46本の細い管として描き、影の計算でも同じ回数描いていました。今はコーンのシェーダーの中で、2方向のらせんまでの距離から凸の筋を計算して陰影をつけています。光の当たり方（GGX）、柔らかい影（5×5のPCF）、色の補正（ACES）もThree.jsの設定に合わせて自分で書き、見た目をほぼ同じにそろえました。

- 読み込み量が約690KB減った（同梱していたThree.jsが不要に）
- クリームが積み上がった状態で、1フレームのJS処理が7.3msから2.8msに短縮
- CPUを4倍遅くした条件（スマホ相当）で、14fpsから32fpsに改善

## きれいにしか巻けない仕組み

最初はコーンを自分で動かして巻くゲームで、上手く動かせないと形が崩れたり、こぼれたりしました。アシストやガイド線を足して精度を上げましたが、物理計算のゆらぎで上のほうがくしゃっと潰れることがあり、「誰が遊んでもきれいなソフトクリームになる」ほうが気持ちいいと判断して作りを変えました。

今は、クリームがノズルから出て落ちる動きは物理計算のまま、コーンに届いたクリームをばねで理想のらせんの位置へ引き寄せて固定しています。コーンは本物のソフトクリームの機械のように自動で回り、ノズルが常に次に巻く位置の真上に来ます。理想の位置に収まったクリームどうしは押し合わないようにして、形が揺れないようにしました。

途中で止めても帯を切らず、もう一度押すと同じ1本の続きとして巻けます。先端を細くするのは完成したときの1回だけです。目標の量に届くと自動で止まり、らせんの最後が中心に寄って先がつんと仕上がります。

## 平らな土台から始まるらせん

一定の高さずつ上がるらせんだと、1巻き目の終わりが始まりの上を通るところにすき間ができ、横から見るとクリームが浮いて見えました。本物のソフトクリームは、まずコーンの上に平らな輪を置いてから上へ巻いていきます。そこで1巻き目はほとんど上がらない平らな土台にし、2巻き目からは1巻きごとにクリーム約1本分ずつ高くなるようにしました。

わざと何十回も止めたり、ランダムにフレーバーを切り替えたり、しぼりながら作業台を回したりしても、5種類すべてのオーダーで整ったらせんになることを確認しています。

## 成果

- どう遊んでも、平らな土台からつんとした先端まで整ったらせんに巻ける
- Three.js版からWebGL2で書き直し、1フレームのJS処理を7.3msから2.8msに短縮
- クリームの管を頂点シェーダーで組み立て、星型の絞り口の筋まで表現
- 量とフレーバーが異なる5種類のオーダーと、オーダーごとの自己ベスト
- 完成品を回して眺め、描き直した結果カードを画像で保存・シェアできる

## リンク

- [サイト](https://wakame.dev/soft-serve/)

## このサイトについて

- [ワカメの詳細プロフィール](https://wakame.dev/ai-profile/index.html.md)
- [llms.txt](https://wakame.dev/llms.txt)
