From 71a1e45dae4548a3096a51ab4c0262e12c7203fa Mon Sep 17 00:00:00 2001 From: Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> Date: Mon, 5 Oct 2026 00:57:59 +0900 Subject: bluebey-studio: 白目が描画されない不具合を修正し、涙を目の設定へ移動 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/bluebey-studio/src/main.js | 4 ++ public/bluebey-studio/src/panel.js | 89 ++++++++++++++++++-------------------- 2 files changed, 45 insertions(+), 48 deletions(-) (limited to 'public/bluebey-studio') diff --git a/public/bluebey-studio/src/main.js b/public/bluebey-studio/src/main.js index d4866c7..e282e9d 100644 --- a/public/bluebey-studio/src/main.js +++ b/public/bluebey-studio/src/main.js @@ -1584,6 +1584,10 @@ async function init() { closedLines: own.closedLines, irisShape: own.irisShape, threeFlip: own.threeFlip === true, + // 白目 / 光彩 are per eye and tri-state: `null` means "the usual" (open + // eyes show their white; the shared 光彩 switch decides the glint). + white: own.white ?? null, + highlight: own.highlight ?? null, // The tears are per eye, so one eye can cry on its own. tear: own.tear ?? 0, tearY: own.tearY ?? 0, diff --git a/public/bluebey-studio/src/panel.js b/public/bluebey-studio/src/panel.js index 6cf8c40..e6f6446 100644 --- a/public/bluebey-studio/src/panel.js +++ b/public/bluebey-studio/src/panel.js @@ -578,6 +578,34 @@ export function buildPanel(app, root) { center: 'eye', onChange: ({ x, y }) => { write((e) => { e.lookX = x; e.lookY = y; }); touched(); }, }); + // 涙: per eye. Linked, one set drives both - size and height match, while the + // sideways position and the tilt mirror so the pair stays symmetric. + const writeTear = (patch) => { + Object.assign(state.face.eyes[primary], patch); + if (mode === 'both') { + const mirrored = { ...patch }; + if (patch.tearX != null) mirrored.tearX = -patch.tearX; + if (patch.tearTilt != null) mirrored.tearTilt = -patch.tearTilt; + Object.assign(state.face.eyes[primary === 'left' ? 'right' : 'left'], mirrored); + } + touched(); + }; + const tear = slider({ + label: '涙', min: 0, max: 1.6, step: 0.01, value: 0, format: (v) => v.toFixed(2), + onInput: (v) => writeTear({ tear: v }), + }); + const tearY = slider({ + label: '涙の高さ', min: -80, max: 140, step: 1, value: 0, format: (v) => `${Math.round(v)}`, + onInput: (v) => writeTear({ tearY: v }), + }); + const tearX = slider({ + label: '涙のよこ位置', min: -150, max: 150, step: 1, value: 0, format: (v) => `${Math.round(v)}`, + onInput: (v) => writeTear({ tearX: v }), + }); + const tearTilt = slider({ + label: '涙の傾き', min: -60, max: 60, step: 1, value: 0, format: (v) => `${Math.round(v)}°`, + onInput: (v) => writeTear({ tearTilt: v }), + }); group.add(open); group.add(shape); @@ -588,6 +616,10 @@ export function buildPanel(app, root) { group.add(eyeX); group.add(controlRow('目線', h('div', { class: 'pad-wrap' }, pad.el, h('p', { class: 'hint', text: 'ドラッグで目線。ダブルクリックで正面に戻ります。' })))); + group.add(tear); + group.add(tearY); + group.add(tearX); + group.add(tearTilt); const syncOne = () => { const e = state.face.eyes[primary]; @@ -602,6 +634,10 @@ export function buildPanel(app, root) { highlight.set(eyeHighlightOf(e)); eyeX.set(e.eyeX ?? 0); pad.set({ x: e.lookX ?? 0, y: e.lookY ?? 0 }); + tear.set(e.tear ?? 0); + tearY.set(e.tearY ?? 0); + tearX.set(e.tearX ?? 0); + tearTilt.set(e.tearTilt ?? 0); }; return { group, sync: syncOne }; }; @@ -615,53 +651,16 @@ export function buildPanel(app, root) { faceSection.add(leftControls.group); faceSection.add(rightControls.group); - // 下まぶた・涙・目線スライダー (per eye) live in こまかい設定; the tears mirror - // onto the other eye while the two are linked. + // 下まぶた (per eye) lives in こまかい設定. const eyeAdvancedWidgets = {}; for (const key of ['left', 'right']) { const label = key === 'left' ? '左の目' : '右の目'; - const otherKey = key === 'left' ? 'right' : 'left'; - const setTear = (patch) => { - Object.assign(state.face.eyes[key], patch); - if (state.face.eyes.linked) { - const mirrored = { ...patch }; - if (patch.tearX != null) mirrored.tearX = -patch.tearX; - if (patch.tearTilt != null) mirrored.tearTilt = -patch.tearTilt; - Object.assign(state.face.eyes[otherKey], mirrored); - } - app.actions.refresh('face'); - sync(); - }; - const tear = slider({ - label: `${label}の涙`, min: 0, max: 1.6, step: 0.01, value: 0, format: (v) => v.toFixed(2), - onInput: (value) => setTear({ tear: value }), - }); - const tearY = slider({ - label: `${label}の涙の高さ`, min: -80, max: 140, step: 1, value: 0, format: (v) => `${Math.round(v)}`, - onInput: (value) => setTear({ tearY: value }), - }); - const tearX = slider({ - label: `${label}の涙のよこ位置`, min: -150, max: 150, step: 1, value: 0, format: (v) => `${Math.round(v)}`, - onInput: (value) => setTear({ tearX: value }), - }); - const tearTilt = slider({ - label: `${label}の涙の傾き`, min: -60, max: 60, step: 1, value: 0, format: (v) => `${Math.round(v)}°`, - onInput: (value) => setTear({ tearTilt: value }), - }); const lowerLid = slider({ label: `${label}の下まぶた`, min: 0, max: 1, step: 0.01, value: 0, format: (v) => v.toFixed(2), onInput: (value) => { state.face.eyes[key].lowerLid = value; app.actions.refresh('face'); }, }); - const lookX = slider({ - label: `${label}の目線(よこ)`, min: -1, max: 1, step: 0.01, value: 0, format: (v) => v.toFixed(2), - onInput: (value) => { state.face.eyes[key].lookX = value; app.actions.refresh('face'); }, - }); - const lookY = slider({ - label: `${label}の目線(たて)`, min: -1, max: 1, step: 0.01, value: 0, format: (v) => v.toFixed(2), - onInput: (value) => { state.face.eyes[key].lookY = value; app.actions.refresh('face'); }, - }); - eyeAdvancedWidgets[key] = { tear, tearY, tearX, tearTilt, lowerLid, lookX, lookY }; - tearWidgets.push(lowerLid.el, lookX.el, lookY.el, tear.el, tearY.el, tearX.el, tearTilt.el); + eyeAdvancedWidgets[key] = { lowerLid }; + tearWidgets.push(lowerLid.el); } // One button to put every eye setting back to the artwork's defaults. The @@ -762,8 +761,8 @@ export function buildPanel(app, root) { const eyeColorBox = details(faceSection.body, '色(白目・瞳・まぶたの線)'); for (const widget of Object.values(eyeColors)) eyeColorBox.add(widget.el); - // 目線・下まぶた・涙 (all per eye) live here with the other extras. - const tearBox = details(eyeAdvanced.body, '目線・下まぶた・涙(左右べつ)'); + // 下まぶた (per eye) lives here with the other extras. + const tearBox = details(eyeAdvanced.body, '下まぶた(左右べつ)'); for (const el of tearWidgets) tearBox.add(el); const eyeSource = selectField({ @@ -2748,13 +2747,7 @@ export function buildPanel(app, root) { for (const key of ['left', 'right']) { const eye = state.face.eyes[key]; const w = eyeAdvancedWidgets[key]; - w.tear.set(eye.tear ?? 0); - w.tearY.set(eye.tearY ?? 0); - w.tearX.set(eye.tearX ?? 0); - w.tearTilt.set(eye.tearTilt ?? 0); w.lowerLid.set(eye.lowerLid ?? state.face.eyes.lowerLid ?? 0); - w.lookX.set(eye.lookX ?? 0); - w.lookY.set(eye.lookY ?? 0); } irisScaleSlider.set(state.face.eyes.irisScale); -- cgit v1.3.1