aboutsummaryrefslogtreecommitdiffhomepage
path: root/public/bluebey-studio/src/faceArt.js
diff options
context:
space:
mode:
authorYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-04 00:43:33 +0900
committerYasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com>2026-10-04 00:43:33 +0900
commit8c430aefc24545c100b34acea2824d837f5e0337 (patch)
tree6e6c823b57936511438379cfed0ce3fbffe90ef3 /public/bluebey-studio/src/faceArt.js
parent3c7fc9271cdaf7b8ee11609d3c4e73df7ba9e0d9 (diff)
bluebey-studio: 顔タブの並び替えと髪の形を追加
顔タブを プリセット→髪→眉→目→見る先→…の順に。頭の模様を「髪」としてほっぺから分離。見る先を目の直下へ。なみを削除し、わけめを7:3分けに、まえがみをとがった形に、まえがみ(逆)を「はちわれ」に改名し、単純なカーブの形を追加。髪を目の前に出すか後ろに回すかを選べるようにした。
Diffstat (limited to 'public/bluebey-studio/src/faceArt.js')
-rw-r--r--public/bluebey-studio/src/faceArt.js46
1 files changed, 21 insertions, 25 deletions
diff --git a/public/bluebey-studio/src/faceArt.js b/public/bluebey-studio/src/faceArt.js
index c4940d4..7b5f7de 100644
--- a/public/bluebey-studio/src/faceArt.js
+++ b/public/bluebey-studio/src/faceArt.js
@@ -796,7 +796,7 @@ function drawCheeks(ctx, spec) {
*/
function drawHeadCover(ctx, spec, limits) {
const shape = spec?.shape ?? 'off';
- if (shape === 'off' || shape === 'none') return;
+ if (shape === 'off' || shape === 'none' || shape === 'wave') return;
const size = clamp(spec.size ?? 1, 0.02, 3);
const left = limits.left;
@@ -828,23 +828,14 @@ function drawHeadCover(ctx, spec, limits) {
const halfSpan = width / 2;
const boundary = (x) => {
const t = clamp((x - cx) / halfSpan, -1, 1);
- if (shape === 'fringe') {
- // Bangs: a soft point dipping in the middle, with side lobes.
- return base + 150 * (1 - Math.abs(t)) - 55 * Math.abs(Math.sin(t * Math.PI));
- }
- if (shape === 'fringe-up') {
- // The mirror image: a fringe that peaks *up* in the middle (a widow's peak
- // or centre part), so more forehead shows in the middle than at the sides.
- return base - 150 * (1 - Math.abs(t)) + 55 * Math.abs(Math.sin(t * Math.PI));
- }
- if (shape === 'wave') {
- // A single smooth sweep across the forehead.
- return base + 120 * Math.sin(t * Math.PI * 0.9 + 0.5);
- }
- if (shape === 'side') {
- // A side part: high on one side, low on the other.
- return base + 260 * t;
- }
+ // まえがみ: a narrow, deep V pointing down the middle (Atom / Mickey).
+ if (shape === 'fringe') return base + 175 * Math.max(0, 1 - Math.abs(t) * 1.6);
+ // はちわれ: the same V upside down - a widow's peak.
+ if (shape === 'fringe-up') return base - 320 * Math.max(0, 1 - Math.abs(t) * 1.5);
+ // カーブ: a plain shallow curve, higher (more hair) round the sides.
+ if (shape === 'curve') return base + 160 * t * t;
+ // わけめ: a 7:3 parting - a step at 30% from the left.
+ if (shape === 'side') return base + 60 - 320 / (1 + Math.exp(-(t + 0.4) * 10));
// `cap`: a rounded helmet, lowest in the middle.
return base - 100 * (1 - t * t);
};
@@ -864,7 +855,7 @@ function drawHeadCover(ctx, spec, limits) {
if (shape === 'side') {
// わけめ: cut a real parting in the hair, so the two halves read as combed
// apart rather than as one smooth sweep.
- const partX = cx - halfSpan * 0.45;
+ const partX = cx - halfSpan * 0.4;
const gw = Math.max(5, width * 0.02) * (0.6 + size);
ctx.save();
ctx.globalCompositeOperation = 'destination-out';
@@ -894,8 +885,8 @@ function drawHeadCover(ctx, spec, limits) {
*/
export function drawHeadCoverWrap(ctx, spec, layout) {
const shape = spec?.shape ?? 'off';
- // `split` is a retired front-plate shape; it has no wrap equivalent.
- if (shape === 'off' || shape === 'none' || shape === 'split') return;
+ // `split` and `wave` are retired front-plate shapes; they have no wrap equal.
+ if (shape === 'off' || shape === 'none' || shape === 'split' || shape === 'wave') return;
const size = clamp(spec.size ?? 1, 0.02, 3);
const W = layout.width;
@@ -924,10 +915,15 @@ export function drawHeadCoverWrap(ctx, spec, layout) {
const cx = layout.offsetX + span * 0.5 + clamp(spec.offsetX ?? 0, -600, 600);
const vBound = (x) => {
const t = clamp((x - cx) / half, -1, 1);
- if (shape === 'fringe') return base + 0.14 * (1 - Math.abs(t)) - 0.05 * Math.abs(Math.sin(t * Math.PI));
- if (shape === 'fringe-up') return base - 0.14 * (1 - Math.abs(t)) + 0.05 * Math.abs(Math.sin(t * Math.PI));
- if (shape === 'wave') return base + 0.10 * Math.sin(t * Math.PI * 0.9 + 0.5);
- if (shape === 'side') return base + 0.20 * t;
+ // まえがみ: a narrow, deep V pointing down the middle (Atom / Mickey).
+ if (shape === 'fringe') return base + 0.15 * Math.max(0, 1 - Math.abs(t) * 1.6);
+ // はちわれ: the same V upside down - a widow's peak.
+ if (shape === 'fringe-up') return base - 0.18 * Math.max(0, 1 - Math.abs(t) * 1.5);
+ // カーブ: a plain shallow curve, lower (more hair) round the sides.
+ if (shape === 'curve') return base + 0.10 * t * t;
+ // わけめ: a 7:3 parting - a step at 30% from the left, so the larger side
+ // sits lower (more hair).
+ if (shape === 'side') return base + 0.08 - 0.16 / (1 + Math.exp(-(t + 0.4) * 10));
return base - 0.07 * (1 - t * t); // `cap`
};