aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/panel.js
diff options
context:
space:
mode:
Diffstat (limited to 'public/bluebey-studio/src/panel.js')
-rw-r--r--public/bluebey-studio/src/panel.js19
1 files changed, 10 insertions, 9 deletions
diff --git a/public/bluebey-studio/src/panel.js b/public/bluebey-studio/src/panel.js
index f82d6bf..3312e9c 100644
--- a/public/bluebey-studio/src/panel.js
+++ b/public/bluebey-studio/src/panel.js
@@ -190,14 +190,17 @@ export function buildPanel(app, root) {
});
const randomFace = () => replace({ face: randomFacePatch() }, 'face');
const randomAll = () => {
- const pose = pick(POSE_PRESETS);
+ // 後ろを向く(180°)や大きく傾くポーズは避ける。見える顔が変わる範囲だけ。
+ const poses = POSE_PRESETS.filter((preset) => {
+ const m = preset.pose?.bones?.master ?? [0, 0, 0];
+ return Math.abs(m[0]) <= 45 && Math.abs(m[1]) <= 40 && Math.abs(m[2]) <= 40;
+ });
+ const pose = pick(poses.length ? poses : POSE_PRESETS);
const theme = pick(THEMES);
app.actions.applyPosePreset?.(pose.id);
app.actions.applyTheme?.(theme.id);
- replace({
- face: randomFacePatch(),
- render: { style: pick(STYLE_DEFS.map((style) => style.value)), mirror: Math.random() < 0.5 },
- }, 'all');
+ // The viewer style (実写/フラット/線画) and 左右反転 are deliberately left alone.
+ replace({ face: randomFacePatch() }, 'face');
sync();
};
@@ -213,7 +216,7 @@ export function buildPanel(app, root) {
topBar.append(
iconButton('元に戻す', 'M4.8 11.5h9.7a5.2 5.2 0 0 1 0 10.4h-3.6M4.8 11.5 9.6 6.7M4.8 11.5 9.6 16.3', () => app.actions.undo()),
iconButton('やり直す', 'M19.2 11.5h-9.7a5.2 5.2 0 0 0 0 10.4h3.6M19.2 11.5 14.4 6.7M19.2 11.5 14.4 16.3', () => app.actions.redo()),
- iconButton('すべてをランダムに', 'M5 4.5h14a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-13a1 1 0 0 1 1-1ZM9 8.5h.01M15 8.5h.01M12 12h.01M9 15.5h.01M15 15.5h.01', () => randomAll()),
+ iconButton('すべてをランダムに', 'M7.2 9.4a2.6 2.6 0 1 1 3.9 2.3c-.9.5-1.3 1.2-1.3 2.1v.4M9.2 17.4h.01M16.8 6.8v6.1M16.8 15.6h.01', () => randomAll()),
);
root.append(topBar);
@@ -1188,15 +1191,13 @@ export function buildPanel(app, root) {
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'); } }),
tongue: slider({ label: '舌の大きさ', min: 0, max: 1.6, step: 0.01, value: 0.96, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.tongue = v; app.actions.refresh('face'); } }),
tonguePos: slider({ label: '舌の位置', min: 0.05, max: 0.95, step: 0.01, value: 0.84, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.tonguePos = v; app.actions.refresh('face'); } }),
- tongueOut: slider({ label: '舌を外に出す', min: 0, max: 1, step: 0.01, value: 0, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.tongueOut = v; app.actions.refresh('face'); } }),
- tongueOutPos: slider({ label: '外に出す舌の位置', min: 0.05, max: 0.95, step: 0.01, value: 0.5, format: (v) => v.toFixed(2), onInput: (v) => { state.face.mouth.tongueOutPos = v; app.actions.refresh('face'); } }),
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'];
for (const key of mouthVisible) faceSection.add(mouthSliders[key].el);
const mouthBox = details(faceSection.body, 'こまかい設定(開き・舌・口角)');
- for (const key of ['open', 'tongue', 'tonguePos', 'tongueOut', 'tongueOutPos', 'corners', 'cornerAngle']) mouthBox.add(mouthSliders[key].el);
+ for (const key of ['open', 'tongue', 'tonguePos', 'corners', 'cornerAngle']) mouthBox.add(mouthSliders[key].el);
mouthBox.add(buttons({
items: [{
id: 'mouthreset',