diff options
| author | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-03 13:39:29 +0900 |
|---|---|---|
| committer | Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> | 2026-10-03 13:39:29 +0900 |
| commit | 34032981f60848940640e5741c9ced41a550c8f1 (patch) | |
| tree | 907e76722f9a62cd24c3093047554417ae76b64c /public/bluebey-studio/src/props.js | |
| parent | 58a00c403ccf4fc114a9b46d89925ea54d574e2a (diff) | |
public/bluebey-studio: ポーズ追加・シーンタブ新設・タブのアイコン化
- ポーズ例に「きおつけ」を追加し、おじぎ/ふかくおじぎを両手下げに、
くびかしげは左足を接地させたままにするよう補正、「てをふる」の動き
を追加、全身の移動スライダーの範囲を拡大
- 「表情」タブを「顔」に改名し、「背景」「舞台」「セリフ」「画面・光」
「画面の情報」をまとめた「シーン」タブを新設
- 各タブをアイコンのみの表示にし、タブらしい見た目に変更(名前はツール
チップと読み上げラベルに)
- 起動時の注意書きと /bluebey/ ページの禁止事項を「イメージを損なう
ような利用(たとえば、攻撃的・差別的・性的・過激な利用、誹謗中傷
など)」に変更
- これまでの未コミット分(背景の追加とWebP化、眼鏡・サングラス、ほっぺ
・頭の模様、缶詰、看板、集中線、輪郭線のズーム追従、スマホ対応、
共有など)を反映
- タッチ用の操作案内の <p> の閉じ位置を修正
Diffstat (limited to 'public/bluebey-studio/src/props.js')
| -rw-r--r-- | public/bluebey-studio/src/props.js | 63 |
1 files changed, 42 insertions, 21 deletions
diff --git a/public/bluebey-studio/src/props.js b/public/bluebey-studio/src/props.js index 5ad958a..a5fcbcc 100644 --- a/public/bluebey-studio/src/props.js +++ b/public/bluebey-studio/src/props.js @@ -192,19 +192,28 @@ const buildMic = prop((group, material) => { }); /** - * 看板. A post, a frame and a blank face. The face is a separate, named child - * tagged `userData.canvasTexture`, so a later feature can paint a CanvasTexture - * onto it without touching the frame - and `applyPropFaceScale` can grow just - * that surface, about its own centre, leaving the frame and posts alone. It is a - * thin box rather than a plane: the outline pass offsets geometry along its - * normals, and a zero-thickness plane gets a visibly doubled rim. + * 看板. A post, a frame and a blank face. The face is a named child tagged + * `userData.canvasTexture`, so a later feature can paint a CanvasTexture onto it + * without hunting for the writable mesh. The face *and* its frame are grouped, + * so `applyPropFaceScale` can grow the whole board about the face's centre while + * the post and base stay put. Both are thin boxes rather than planes: the outline + * pass offsets geometry along its normals, and a zero-thickness plane gets a + * visibly doubled rim. */ const buildSign = prop((group, material) => { addBox(group, material('accent'), [0.52, 0.10, 0.52], [0, 0.05, 0]); addBox(group, material('wood'), [0.16, 1.62, 0.16], [0, 0.91, 0]); - addBox(group, material('accent'), [1.42, 0.98, 0.12], [0, 2.21, 0]); - const face = addBox(group, material('paper'), [1.18, 0.76, 0.08], [0, 2.21, 0.06]); + // The board is one group so the face and its frame scale together, about the + // board's own centre - which is also the face's centre. + const board = new THREE.Group(); + board.name = 'sign-board'; + board.userData.faceScaleGroup = true; + board.position.set(0, 2.21, 0); + group.add(board); + + addBox(board, material('accent'), [1.42, 0.98, 0.12], [0, 0, 0]); + const face = addBox(board, material('paper'), [1.18, 0.76, 0.08], [0, 0, 0.06]); face.name = 'sign-face'; face.userData.canvasTexture = true; }); @@ -284,14 +293,19 @@ const buildCan = prop((group, material) => { addCylinder(group, material('metal', 0.45), 0.132, 0.132, 0.012, [0, 0.422, 0], 16); // The one lid, peeled back on a hinge at the back of the mouth so its - // underside shows. It is twisted slightly sideways so it does not read as a - // knob sitting straight up on the can. + // underside shows. The hinge sits *on* the can's back rim and the disc is + // placed so its own rim passes through that same point (its centre is one + // radius in front of the hinge), so opening the hinge rotates the lid about + // its edge - the two rims stay joined instead of the lid floating in mid-air. + // It is twisted slightly sideways so it does not read as a knob sitting + // straight up on the can. + const lidRadius = 0.132; const hinge = new THREE.Group(); - hinge.position.set(0, 0.42, -0.135); + hinge.position.set(0, 0.42, -lidRadius); hinge.rotation.x = -1.05; hinge.rotation.z = 0.4; group.add(hinge); - addCylinder(hinge, material('metal', 0.9), 0.132, 0.132, 0.018, [0, 0.12, 0], 18); + addCylinder(hinge, material('metal', 0.9), lidRadius, lidRadius, 0.018, [0, 0, lidRadius], 18); group.rotation.z = 0.05; }); @@ -327,8 +341,9 @@ export const PROP_DEFAULTS = { podium: { x: -2.1, y: 0, z: 1.9, rotY: 0.30, scale: 1 }, desk: { x: -2.6, y: 0, z: 0.5, rotY: 0.40, scale: 1 }, mic: { x: 2.0, y: 0, z: 1.8, rotY: -0.40, scale: 1 }, - // `faceScale` only means something for a 看板: it grows the writing surface - // alone, so the frame and posts stay put. The panel owns that control. + // `faceScale` only means something for a 看板: it grows the writing area (the + // face and its frame) together, so the post and base stay put. The panel owns + // that control. sign: { x: 2.9, y: 0, z: 0.4, rotY: -0.25, scale: 1, faceScale: 1 }, plant: { x: -2.0, y: 0, z: -1.8, rotY: 0.25, scale: 1 }, box: { x: 2.0, y: 0, z: -1.7, rotY: 0.55, scale: 1 }, @@ -419,21 +434,27 @@ export function propFace(group) { } /** - * Scale the writing surface about its own centre, so only the 看板's face grows - * and its frame and posts stay where they are. `addBox` puts the mesh's origin at - * the box centre, which is what makes this a scale about the centre rather than - * about the prop's base. + * Scale the writing area - the 看板's face *and* the frame around it - about the + * board's own centre, so the post and base stay where they are. A prop that tags + * a group `faceScaleGroup` is scaled as a whole; anything else falls back to the + * writable mesh alone. `addBox` puts a mesh's origin at the box centre and the + * 看板's board group sits at the face centre, which is what makes this a scale + * about the centre rather than about the prop's base. * * WHY this is applied from the panel: the app rebuilds every prop from the state * (`applyProps` in src/main.js) and hands `buildProp` only the whole-prop scale, * so a per-item `faceScale` has to be re-applied to the fresh mesh afterwards. */ export function applyPropFaceScale(group, faceScale) { - const face = propFace(group); - if (!face) return; + let target = null; + group?.traverse?.((object) => { + if (!target && object.userData?.faceScaleGroup) target = object; + }); + target ??= propFace(group); + if (!target) return; const value = Number(faceScale); const scale = Number.isFinite(value) ? Math.min(4, Math.max(0.2, value)) : 1; - face.scale.setScalar(scale); + target.scale.setScalar(scale); } /** The world-space box the prop occupies; the app drops its contact shadow from it. */ |
