diff options
| author | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-05 14:21:12 +0900 |
|---|---|---|
| committer | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-05 14:21:12 +0900 |
| commit | 8598b20ff6ebd68bf139fc361d5b311f7a553882 (patch) | |
| tree | a7c6a7a8a9758fdbf6f3255e39de18b6a45f6912 /public/bluebey-studio/src | |
| parent | 174886a483d90756b1320c12aef0e6f296c6d425 (diff) | |
bluebey-studio: 目の形の反映を修正、まぶたに高さ追加・まつげ実装、キャッシュ対策
レンダラーへ shape を渡しておらず目の形ボタンが効かなかったのを修正。上まぶた・下まぶたの高さを「まぶた」グループへ。まつげを追加。bluebey-studio配下のHTML/JS/CSSをno-cacheにし、更新時に古い版が残らないようにした。
Diffstat (limited to 'public/bluebey-studio/src')
| -rw-r--r-- | public/bluebey-studio/src/face.js | 1 | ||||
| -rw-r--r-- | public/bluebey-studio/src/faceArt.js | 20 | ||||
| -rw-r--r-- | public/bluebey-studio/src/main.js | 3 | ||||
| -rw-r--r-- | public/bluebey-studio/src/panel.js | 39 | ||||
| -rw-r--r-- | public/bluebey-studio/src/presets.js | 1 |
5 files changed, 50 insertions, 14 deletions
diff --git a/public/bluebey-studio/src/face.js b/public/bluebey-studio/src/face.js index b468cd5..ac48527 100644 --- a/public/bluebey-studio/src/face.js +++ b/public/bluebey-studio/src/face.js @@ -237,6 +237,7 @@ export class Face { lowerLid: p.eyes.lowerLid, lidShape: p.eyes.lidShape, lidTilt: p.eyes.lidTilt, + lashes: p.eyes.lashes, brow: p.eyes.brow, // ほっぺ and 頭の模様 are shared by the whole face, so they travel with // the other shared eye fields (see `drawEyes` in src/faceArt.js). diff --git a/public/bluebey-studio/src/faceArt.js b/public/bluebey-studio/src/faceArt.js index 04dd6e3..765c0db 100644 --- a/public/bluebey-studio/src/faceArt.js +++ b/public/bluebey-studio/src/faceArt.js @@ -130,6 +130,8 @@ export const EYE_LAYOUT = { armX: 104, }, arch: { edgesUp: 8, apexUp: 44 }, + // まつげ: a few strokes flicking out from the upper-outer lid (see drawEyes). + lash: { length: 34, width: 9, angles: [26, 52, 78] }, }; /** @@ -1540,6 +1542,24 @@ export function drawEyes(ctx, p) { ctx.restore(); } + // --- まつげ -------------------------------------------------------- + // Short strokes flicking outwards from the upper-outer lid. They sit outside + // the eyeball, so they are drawn after the lid block and are not clipped. + if (style.lashes) { + const outDir = -eye.towardNose; + for (const deg of EYE_LAYOUT.lash.angles) { + const t = (deg * Math.PI) / 180; + const ux = outDir * Math.cos(t); + const uy = -Math.sin(t); + const r0 = eye.r * 0.96; + const r1 = r0 + EYE_LAYOUT.lash.length; + strokePolyline(ctx, [ + { x: eye.cx + ux * r0, y: eye.cy + uy * r0 }, + { x: eye.cx + ux * r1, y: eye.cy + uy * r1 }, + ], { color: lineColor, width: EYE_LAYOUT.lash.width }); + } + } + // --- outline (line-art mode only) --------------------------------- if (line) strokeCircle(ctx, eye.cx, eye.cy, eye.r, lineColor, lidWidth * 0.75); } diff --git a/public/bluebey-studio/src/main.js b/public/bluebey-studio/src/main.js index 6b8d005..d4ef4f2 100644 --- a/public/bluebey-studio/src/main.js +++ b/public/bluebey-studio/src/main.js @@ -1627,6 +1627,9 @@ async function init() { const eyeFor = (key) => { const own = eyes[key]; return { + // Which artwork this eye shows (ふつう / 1〜3線 / 3の目 / わらう / ハート). + // The renderer chooses the shut artwork from this, so it must travel. + shape: own.shape, open: clamp01(own.open * openScale), lookX: clamp(own.lookX + drift.x + aimOffset.x, -1, 1), lookY: clamp(own.lookY + drift.y + aimOffset.y, -1, 1), diff --git a/public/bluebey-studio/src/panel.js b/public/bluebey-studio/src/panel.js index bc8e243..f377d16 100644 --- a/public/bluebey-studio/src/panel.js +++ b/public/bluebey-studio/src/panel.js @@ -531,15 +531,6 @@ export function buildPanel(app, root) { const touched = () => { app.actions.refresh('face'); sync(); }; const group = eyeGroup(mode === 'both' ? '両目' : (mode === 'left' ? '左の目' : '右の目')); - const open = slider({ - label: '上まぶたの高さ', min: 0, max: 1, step: 0.01, value: 1, - format: (v) => (v < 0.02 ? '閉じ' : v > 0.98 ? '開き' : `${Math.round(v * 100)}%`), - onInput: (v) => { write((e) => { e.open = v; }); touched(); }, - }); - const lowerLid = slider({ - label: '下まぶたの高さ', min: 0, max: 1, step: 0.01, value: 0, format: (v) => v.toFixed(2), - onInput: (v) => { write((e) => { e.lowerLid = v; }); touched(); }, - }); // 目の形: the artwork the eye shows. A shut shape is drawn with the lids open, // so 上まぶたの高さ can then be lowered onto it. const shape = segmented({ @@ -626,8 +617,6 @@ export function buildPanel(app, root) { onInput: (v) => writeTear({ tearTilt: v }), }); - group.add(open); - group.add(lowerLid); group.add(shape); group.add(heartColor); group.add(size); @@ -645,8 +634,6 @@ export function buildPanel(app, root) { const syncOne = () => { const e = state.face.eyes[primary]; const shapeValue = eyeShapeOf(e); - open.set(e.open); - lowerLid.set(e.lowerLid ?? state.face.eyes.lowerLid ?? 0); shape.set(shapeValue); heartColor.set(state.face.eyes.heartColor ?? '#e0344f'); heartColor.el.style.display = shapeValue === 'heart' ? '' : 'none'; @@ -684,6 +671,18 @@ export function buildPanel(app, root) { value: 'curve', onChange: (value) => { state.face.eyes.lidShape = value; app.actions.refresh('face'); }, }); + // The lid heights write both eyes together: they live in the まぶた group, which + // is shared, while 目の形 and the rest stay per eye below. + const setBothEyes = (patch) => { for (const k of ['left', 'right']) Object.assign(state.face.eyes[k], patch); }; + const lidOpenSlider = slider({ + label: '上まぶたの高さ', min: 0, max: 1, step: 0.01, value: 1, + format: (v) => (v < 0.02 ? '閉じ' : v > 0.98 ? '開き' : `${Math.round(v * 100)}%`), + onInput: (v) => { setBothEyes({ open: v }); app.actions.refresh('face'); }, + }); + const lidLowerSlider = slider({ + label: '下まぶたの高さ', min: 0, max: 1, step: 0.01, value: 0, format: (v) => v.toFixed(2), + onInput: (v) => { setBothEyes({ lowerLid: v }); app.actions.refresh('face'); }, + }); const lidWidthSlider = slider({ label: 'まぶたの太さ', min: 0, max: 30, step: 1, value: 14, format: (v) => `${Math.round(v)}`, onInput: (value) => { state.face.eyes.lidWidth = value; app.actions.refresh('face'); }, @@ -692,9 +691,17 @@ export function buildPanel(app, root) { label: 'まぶたの傾き', min: -40, max: 40, step: 1, value: 0, format: (v) => `${Math.round(v)}°`, onInput: (value) => { state.face.eyes.lidTilt = value; app.actions.refresh('face'); }, }); + const lashesToggle = check({ + label: 'まつげをつける', + value: false, + onChange: (v) => { state.face.eyes.lashes = v; app.actions.refresh('face'); }, + }); lidGroup.add(lidShapeSegment.el); + lidGroup.add(lidOpenSlider.el); + lidGroup.add(lidLowerSlider.el); lidGroup.add(lidWidthSlider.el); lidGroup.add(lidTiltSlider.el); + lidGroup.add(controlRow(null, lashesToggle.el, { wide: true })); lidGroup.add(hint('「直線(平ら)」にすると、まぶたが平らに下りてきます。' + '「まぶたの傾き」で、細めた目を左右反転で傾けられます。')); @@ -734,7 +741,8 @@ export function buildPanel(app, root) { }], })); - faceSection.add(hint('「左右を連動させる」を入れると「両目」の設定が1つだけ出て、上まぶた・下まぶた・目の形・大きさ・白目・光彩・目線が両目でそろいます。' + faceSection.add(hint('「まぶた」は両目で共通です。「左右を連動させる」を入れると「両目」の設定が1つだけ出て、' + + '目の形・大きさ・白目・光彩・目線が両目でそろいます。' + 'はずすと「左の目」「右の目」の設定がそれぞれに出て、目線のパッドも2つになります。')); const eyeColors = { @@ -2769,6 +2777,9 @@ export function buildPanel(app, root) { lidWidthSlider.set(state.face.eyes.lidWidth ?? 14); lidShapeSegment.set(state.face.eyes.lidShape ?? 'curve'); lidTiltSlider.set(state.face.eyes.lidTilt ?? 0); + lidOpenSlider.set(state.face.eyes.left.open ?? 1); + lidLowerSlider.set(state.face.eyes.left.lowerLid ?? state.face.eyes.lowerLid ?? 0); + lashesToggle.set(state.face.eyes.lashes === true); browToggle.set(state.face.eyes.brow.enabled); browSliders.angle.set(state.face.eyes.brow.angle); browSliders.height.set(state.face.eyes.brow.height); diff --git a/public/bluebey-studio/src/presets.js b/public/bluebey-studio/src/presets.js index a8b10ec..ccd6237 100644 --- a/public/bluebey-studio/src/presets.js +++ b/public/bluebey-studio/src/presets.js @@ -207,6 +207,7 @@ export function defaultState() { highlight: true, lidWidth: 14, lowerLid: 0, + lashes: false, // How the closing eyelid is drawn: `curve` is the soft, rounded lid; `flat` // is a straight lid edge (the hard, narrowed look). `lidTilt` rotates the // narrowed eye. See faceArt.js. |
