diff options
| author | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-04 01:09:24 +0900 |
|---|---|---|
| committer | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-04 01:09:24 +0900 |
| commit | b939182d5a51b8535dd411a754c2088f7f1bafff (patch) | |
| tree | fd9cf4c50cd9902552632efc9ef6792adf363f45 /public/bluebey-studio/src/panel.js | |
| parent | e9b8f3194c8604f5d0826df1b1e6a17cf27f68f7 (diff) | |
bluebey-studio: ゴル風の眉画像と口の長さを追加
髭と同じ仕組みで、右側だけの眉画像(assets/brows/gol-right.png)を左右に描けるようにした(「ゴル風」で自動適用、チェックで切替)。口に「口の長さ」スライダーを追加。
Diffstat (limited to 'public/bluebey-studio/src/panel.js')
| -rw-r--r-- | public/bluebey-studio/src/panel.js | 14 |
1 files changed, 13 insertions, 1 deletions
diff --git a/public/bluebey-studio/src/panel.js b/public/bluebey-studio/src/panel.js index 237d6c8..406bbfb 100644 --- a/public/bluebey-studio/src/panel.js +++ b/public/bluebey-studio/src/panel.js @@ -836,6 +836,7 @@ export function buildPanel(app, root) { // it, with the two brows sitting close together. Object.assign(state.face.eyes.brow, { enabled: true, + image: true, angle: 34, height: 2, length: 1.7, @@ -874,6 +875,15 @@ export function buildPanel(app, root) { ], })); + const browImageToggle = check({ + label: 'ゴル風の画像を使う', + value: false, + onChange: (value) => { state.face.eyes.brow.image = value; app.actions.refresh('face'); }, + }); + faceSection.add(controlRow(null, browImageToggle.el, { wide: true })); + faceSection.add(hint('読み込んだ画像(assets/brows/gol-right.png)を眉として左右に描きます。' + + '「ゴル風」を押すと自動で入ります。画像が無いときは今までの線で描きます。')); + // --- glasses / sunglasses (drawn into the same texture as the eyes and brows) faceSection = faceTabSections.glasses; faceSection.add(hint('眼鏡やサングラスを、目や眉と同じ絵にかけます。' @@ -1226,6 +1236,7 @@ export function buildPanel(app, root) { open: slider({ label: '口の開き', min: 0, max: 1, step: 0.01, value: 0, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.open = v; app.actions.refresh('face'); } }), round: slider({ label: '丸く開く(Oの口)', min: 0, max: 1, step: 0.01, value: 0, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.round = v; app.actions.refresh('face'); } }), width: slider({ label: '口の幅', min: 0.2, max: 1.6, step: 0.01, value: 1, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.width = v; app.actions.refresh('face'); } }), + length: slider({ label: '口の長さ', min: 0.2, max: 2.5, step: 0.01, value: 1, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.length = v; app.actions.refresh('face'); } }), thickness: slider({ label: '口の太さ', min: 0.2, max: 3, step: 0.01, value: 1, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.thickness = v; app.actions.refresh('face'); } }), tilt: slider({ label: '口の傾き', min: -30, max: 30, step: 1, value: 0, format: (v) => `${Math.round(v)}°`, onInput: (v) => { state.face.mouth.tilt = v; app.actions.refresh('face'); } }), offsetY: slider({ label: '口の高さ', min: -140, max: 140, step: 1, value: 0, format: (v) => `${Math.round(v)}`, onInput: (v) => { state.face.mouth.offsetY = v; app.actions.refresh('face'); } }), @@ -1234,7 +1245,7 @@ export function buildPanel(app, root) { corners: slider({ label: '口角の長さ', min: 0, max: 1.6, step: 0.01, value: 0.71, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.corners = v; app.actions.refresh('face'); } }), cornerAngle: slider({ label: '口角の角度', min: -70, max: 70, step: 1, value: -8, format: (v) => `${Math.round(v)}°`, onInput: (v) => { state.face.mouth.cornerAngle = v; app.actions.refresh('face'); } }), }; - const mouthVisible = ['smile', 'round', 'width', 'thickness', 'tilt', 'offsetY']; + const mouthVisible = ['smile', 'round', 'width', 'length', 'thickness', 'tilt', 'offsetY']; for (const key of mouthVisible) faceSection.add(mouthSliders[key].el); const mouthBox = details(faceSection.body, 'こまかい設定(開き・舌・口角)'); for (const key of ['open', 'tongue', 'tonguePos', 'corners', 'cornerAngle']) mouthBox.add(mouthSliders[key].el); @@ -2695,6 +2706,7 @@ export function buildPanel(app, root) { browSliders.spacing.set(state.face.eyes.brow.spacing ?? 0); browSliders.curve.set(state.face.eyes.brow.curve); browSliders.taper.set(state.face.eyes.brow.taper ?? 1); + browImageToggle.set(state.face.eyes.brow.image === true); browColor.set(state.face.eyes.brow.color); glassesToggle.set(state.face.eyes.glasses.enabled === true); glassesKindSegment.set(state.face.eyes.glasses.kind ?? 'glasses'); |
