From 257516e2bde90e65439d01f19434cd2d9d5a03f7 Mon Sep 17 00:00:00 2001 From: Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> Date: Mon, 5 Oct 2026 14:51:36 +0900 Subject: bluebey-studio: 帽子切替のエラー修正とGLB帽子インポート、閉じ目の目線範囲・まつげ位置を調整 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 帽子切替時にトラバース中でハルを外して子がundefinedになる不具合を修正。GLBの帽子モデルを読み込めるようにし、なしで解除できるようにした。閉じ目の目線範囲を通常並みに広げ、まつげを上まぶたの外側へ配置。 --- public/bluebey-studio/src/panel.js | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) (limited to 'public/bluebey-studio/src/panel.js') diff --git a/public/bluebey-studio/src/panel.js b/public/bluebey-studio/src/panel.js index 2b762f1..093386f 100644 --- a/public/bluebey-studio/src/panel.js +++ b/public/bluebey-studio/src/panel.js @@ -1674,15 +1674,41 @@ export function buildPanel(app, root) { /* ------------------------------------------------------------- 帽子 */ const hatSection = section(tabView, '帽子'); - hatSection.add(hint('ぶるべーの頭に帽子をかぶせます。もう一度「なし」を選ぶと外れます。')); + hatSection.add(hint('ぶるべーの頭に帽子をかぶせます。「なし」を選ぶと外れます。')); const hatSegment = segmented({ label: '帽子', options: HAT_LIBRARY.map((hat) => ({ value: hat.id, label: hat.label })), value: 'none', - onChange: (value) => { state.face.hat.kind = value; app.actions.refresh('all'); }, + onChange: (value) => { + state.face.hat.kind = value; + // Picking one of the built-in hats (including なし) also clears any GLB hat + // the user imported, so なし really removes the hat. + state.face.hat.custom = false; + app.actions.refresh('all'); + }, }); hatSection.add(hatSegment.el); - syncers.push(() => hatSegment.set(state.face.hat?.kind ?? 'none')); + syncers.push(() => hatSegment.set(state.face.hat?.custom === true ? 'none' : (state.face.hat?.kind ?? 'none'))); + + // 帽子モデル(GLB)の取り込み。頭に乗るよう自動で位置と大きさを合わせる。 + const hatFilePicker = h('input', { type: 'file', accept: '.glb,.gltf,model/gltf-binary,model/gltf+json', style: { display: 'none' } }); + hatFilePicker.addEventListener('change', async () => { + const file = hatFilePicker.files?.[0]; + hatFilePicker.value = ''; + if (!file) return; + try { + await app.actions.loadHatModel(file); + toast(`帽子「${file.name}」を読み込みました`); + } catch (error) { + console.error(error); + toast('帽子モデルを読み込めませんでした(GLBをお使いください)'); + } + }); + hatSection.add(hatFilePicker); + hatSection.add(buttons({ + items: [{ id: 'hatfile', label: '帽子モデルを読み込む(GLB)', onClick: () => hatFilePicker.click() }], + })); + hatSection.add(hint('GLBの帽子を頭に乗せます。大きさと位置は自動で合わせます。')); const hatBox = details(hatSection.body, '位置と傾き'); const hatSliders = { -- cgit v1.3.1