From c23c8fb5c547540c0705bef900340c9a6e358126 Mon Sep 17 00:00:00 2001 From: Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> Date: Sat, 3 Oct 2026 14:36:10 +0900 Subject: public/bluebey-studio: 鼻ちょうちんを球に、寝ている動きを追加、見出しにアイコン MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 鼻ちょうちんを単純な球にし、奥行き(おくゆき)も設定できるように - 「ねている」の動きを追加。呼吸に合わせて鼻ちょうちんが膨らみ・縮む - 各タブの見出し(メニュー一覧)にアイコンを追加 - 操作案内の文言を実態(ぶるべーをドラッグで移動)に合わせて更新 --- public/bluebey-studio/src/main.js | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) (limited to 'public/bluebey-studio/src/main.js') 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(); -- cgit v1.3.1