aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/main.js
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-03 14:36:10 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-03 14:36:10 +0900
commitc23c8fb5c547540c0705bef900340c9a6e358126 (patch)
treeabe4787077265e9d32690183900126fadbc81d4e /public/bluebey-studio/src/main.js
parenta1337fab526a9babd5c492537bd7aee4cc5e7d26 (diff)
public/bluebey-studio: 鼻ちょうちんを球に、寝ている動きを追加、見出しにアイコン
- 鼻ちょうちんを単純な球にし、奥行き(おくゆき)も設定できるように - 「ねている」の動きを追加。呼吸に合わせて鼻ちょうちんが膨らみ・縮む - 各タブの見出し(メニュー一覧)にアイコンを追加 - 操作案内の文言を実態(ぶるべーをドラッグで移動)に合わせて更新
Diffstat (limited to 'public/bluebey-studio/src/main.js')
-rw-r--r--public/bluebey-studio/src/main.js39
1 files changed, 22 insertions, 17 deletions
diff --git a/public/bluebey-studio/src/main.js b/public/bluebey-studio/src/main.js
index 68df32c..1f6ad6e 100644
--- a/public/bluebey-studio/src/main.js
+++ b/public/bluebey-studio/src/main.js
@@ -275,14 +275,15 @@ async function init() {
if (!group) return;
group.visible = snot?.enabled === true;
if (!group.visible) return;
- group.scale.setScalar(Number.isFinite(snot.size) ? snot.size : 1);
- const base = group.userData.base;
const k = 0.01; // artwork px -> world units, enough to nudge the bubble
- group.position.set(
- base.x + (snot.offsetX ?? 0) * k,
- base.y + (snot.offsetY ?? 0) * k,
- base.z,
- );
+ const target = group.userData.baseWorld.clone().add(new THREE.Vector3(
+ (snot.offsetX ?? 0) * k,
+ (snot.offsetY ?? 0) * k,
+ (snot.offsetZ ?? 0) * k,
+ ));
+ group.position.copy(group.userData.bone.worldToLocal(target));
+ group.userData.baseScale = Number.isFinite(snot.size) ? snot.size : 1;
+ group.scale.setScalar(group.userData.baseScale);
group.userData.material.color.set(snot.color ?? '#dfe8ff');
}
@@ -321,16 +322,12 @@ async function init() {
});
const group = new THREE.Group();
group.name = 'snot-bubble';
- const bubble = new THREE.Mesh(new THREE.SphereGeometry(radius * 1.05, 28, 20), material);
- const neck = new THREE.Mesh(new THREE.SphereGeometry(radius * 0.42, 20, 14), material);
- group.add(bubble, neck);
+ const bubble = new THREE.Mesh(new THREE.SphereGeometry(radius * 1.15, 28, 20), material);
+ group.add(bubble);
const bone = master.bone;
- const bubbleLocal = bone.worldToLocal(centre.clone().add(new THREE.Vector3(radius * 1.9, -radius * 0.85, radius * 0.7)));
- const noseLocal = bone.worldToLocal(centre.clone());
- group.position.copy(bubbleLocal);
- // The neck lump sits partway back towards the nose, so the two read as joined.
- neck.position.copy(noseLocal).sub(bubbleLocal).multiplyScalar(0.45);
- group.userData = { bubble, neck, material, base: bubbleLocal.clone() };
+ const baseWorld = centre.clone().add(new THREE.Vector3(radius * 1.9, -radius * 0.85, radius * 0.7));
+ group.position.copy(bone.worldToLocal(baseWorld.clone()));
+ group.userData = { bubble, material, bone, baseWorld, baseScale: 1 };
group.visible = false;
bone.add(group);
return group;
@@ -1244,12 +1241,20 @@ async function init() {
if (snotBubble) {
const snot = state.face.eyes.snot;
- const sig = `${snot.enabled}|${snot.size}|${snot.offsetX}|${snot.offsetY}|${snot.color}`;
+ const sig = `${snot.enabled}|${snot.size}|${snot.offsetX}|${snot.offsetY}|${snot.offsetZ}|${snot.color}`;
if (sig !== snotSignature) {
snotSignature = sig;
applySnotBubble(snotBubble, snot);
app.needsRender = true;
}
+ // The sleeping breath swells the bubble; `snotScale` is 1 otherwise.
+ if (snotBubble.visible) {
+ const scale = (snotBubble.userData.baseScale ?? 1) * (animator.snotScale ?? 1);
+ if (snotBubble.scale.x !== scale) {
+ snotBubble.scale.setScalar(scale);
+ app.needsRender = true;
+ }
+ }
}
const params = buildFaceParams();