aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/panel.js
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-04 01:09:24 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-04 01:09:24 +0900
commitb939182d5a51b8535dd411a754c2088f7f1bafff (patch)
treefd9cf4c50cd9902552632efc9ef6792adf363f45 /public/bluebey-studio/src/panel.js
parente9b8f3194c8604f5d0826df1b1e6a17cf27f68f7 (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.js14
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');