aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/faceArt.js
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-03 14:56:41 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-03 14:56:41 +0900
commitc6d1df09c66bcfe8388651866d26ed5d05b4d2d2 (patch)
tree8f55d24a31ec22c1c904157e41ba13cdd88ab420 /public/bluebey-studio/src/faceArt.js
parent27483644d7ba9e819dbb5f64844270dd499f45ff (diff)
public/bluebey-studio: 鼻ちょうちんの追従とひげを修正
鼻ちょうちんの位置が、カメラ移動やポーズ変更のあとに飛ぶ問題を修正。位置はボーン局所座標で持ち、スライダーのオフセットは体の向きに追従させた。寝ている動きでは鼻ちょうちんを自動で表示する。 ひげは「猫」に左右の間隔スライダーを追加し、太さを変えずに大きくできるようにした。カイゼルは先をダリ風のカールにした。
Diffstat (limited to 'public/bluebey-studio/src/faceArt.js')
-rw-r--r--public/bluebey-studio/src/faceArt.js36
1 files changed, 29 insertions, 7 deletions
diff --git a/public/bluebey-studio/src/faceArt.js b/public/bluebey-studio/src/faceArt.js
index a92482a..8d20cda 100644
--- a/public/bluebey-studio/src/faceArt.js
+++ b/public/bluebey-studio/src/faceArt.js
@@ -869,7 +869,7 @@ function drawBeard(ctx, spec, lineOnly = false) {
const shape = spec?.shape ?? 'off';
if (shape === 'off' || shape === 'none') return;
const size = clamp(spec.size ?? 1, 0.2, 3);
- const cx = BEARD_LAYOUT.cx + clamp(spec.offsetX ?? 0, -600, 600);
+ const cx = BEARD_LAYOUT.cx;
const cy = BEARD_LAYOUT.cy + clamp(spec.offsetY ?? 0, -600, 600);
const w = BEARD_LAYOUT.width * size;
const color = spec.color ?? '#3a2a4a';
@@ -895,8 +895,24 @@ function drawBeard(ctx, spec, lineOnly = false) {
{ x: cx + w * 0.28, y: cy + w * 0.07 },
{ x: cx + w * 0.5, y: cy - w * 0.02 },
], lw * 2.6);
- stroke([{ x: cx - w * 0.5, y: cy - w * 0.02 }, { x: cx - w * 0.62, y: cy - w * 0.16 }], lw * 1.4);
- stroke([{ x: cx + w * 0.5, y: cy - w * 0.02 }, { x: cx + w * 0.62, y: cy - w * 0.16 }], lw * 1.4);
+ const curlAt = (dir) => {
+ // A little inward-turning spiral at the tip: the Dalí curl.
+ const ex = cx + dir * w * 0.5;
+ const ey = cy - w * 0.02;
+ const r0 = lw * 0.5;
+ const r1 = w * 0.17;
+ const steps = 22;
+ const points = [];
+ for (let i = 0; i <= steps; i += 1) {
+ const t = i / steps;
+ const a = -Math.PI / 2 + dir * Math.PI * 2 * 1.4 * t;
+ const r = r0 + (r1 - r0) * t;
+ points.push({ x: ex + dir * Math.cos(a) * r, y: ey + Math.sin(a) * r });
+ }
+ stroke(points, lw * 1.25);
+ };
+ curlAt(-1);
+ curlAt(1);
return;
}
if (shape === 'apron') {
@@ -918,13 +934,19 @@ function drawBeard(ctx, spec, lineOnly = false) {
}
return;
}
- // ねこ: three whiskers fanned out on each side of the muzzle.
+ // ねこ: three whiskers a side, growing out of the cheeks with a gap left in the
+ // middle (like a cat's). The thickness is fixed, so `size` makes the whiskers
+ // longer and wider-spread without making them fatter, and `spacing` opens the
+ // gap between the left and right.
+ const whisker = 8;
+ const inner = w * 0.30 + clamp(spec.spacing ?? 0, 0, 800);
+ const outer = Math.max(inner + w * 0.2, w * 0.68);
for (const dir of [-1, 1]) {
for (let i = 0; i < 3; i += 1) {
stroke([
- { x: cx + dir * w * 0.08, y: cy + w * 0.04 },
- { x: cx + dir * w * 0.62, y: cy + w * 0.04 + (i - 1) * w * 0.18 },
- ], lw * 0.9);
+ { x: cx + dir * inner, y: cy + (i - 1) * w * 0.16 },
+ { x: cx + dir * outer, y: cy + (i - 1) * w * 0.24 },
+ ], whisker);
}
}
}