// ==UserScript== // @name Muse (muse.ai) - Top Avatar Enlarger // @namespace https://muse.ai/ // @version 4.0.0 // @description muse.ai 上部アバターのフレーム本体(role="button", 56px)を直接拡大します。サイドバー(role="img", 128px)には適用しません。非公式のユーザースクリプトです。サイズは AVATAR_SIZE で変更できます。 // @license MIT // @match https://muse.ai/* // @match https://*.muse.ai/* // @run-at document-idle // @grant none // @noframes // ==/UserScript== (function () { 'use strict'; /* ================= 設定 ================= */ const AVATAR_SIZE = 300; // 拡大後の直径(px)。変えたい場合はこの数字だけ変更してください const DEBUG = false; /* ======================================== */ // 上部フレームの確定セレクタ(実物HTMLより): //
// サイドバー側は role="img" / 128px なので、role="button" で明確に区別できる const FRAME_SELECTOR = '[data-hatch-avatar-interaction="true"][role="button"]'; const STAGE_SELECTOR = '[data-hatch-avatar-stage="chat-nav"]'; const NAME_SPACE = 32; // ステージ設計: min-h 88px - 56px = 名前分 32px function cleanupOld() { document.querySelectorAll('[data-muse-avatar-enlarged]').forEach((el) => { ['width', 'height', 'min-width', 'min-height', 'max-width', 'max-height', 'flex'] .forEach((p) => el.style.removeProperty(p)); el.removeAttribute('data-muse-avatar-enlarged'); }); document.querySelectorAll('[data-muse-avatar-scaled]').forEach((el) => { el.style.removeProperty('transform'); el.style.removeProperty('transform-origin'); el.style.removeProperty('z-index'); el.removeAttribute('data-muse-avatar-scaled'); }); } function setSize(el, px) { ['width', 'height', 'min-width', 'min-height', 'max-width', 'max-height'] .forEach((p) => el.style.setProperty(p, px + 'px', 'important')); } // フレームと同じ親の中にある付属要素(名前の吹き出し等)は、 // top の位置が元のフレームサイズ基準で置かれているので、増えた分だけ下げる function shiftAccessories(frame, delta) { const root = frame.parentElement; if (!root || delta === 0) return; root.querySelectorAll('[data-hatch-avatar-accessory]').forEach((el) => { if (frame.contains(el)) return; if (!el.dataset.museOriginalTop) { const top = parseFloat(el.style.top); if (!Number.isFinite(top)) return; el.dataset.museOriginalTop = String(top); } const newTop = parseFloat(el.dataset.museOriginalTop) + delta; el.style.setProperty('top', newTop + 'px', 'important'); }); } function enlargeStage() { const stage = document.querySelector(STAGE_SELECTOR); if (!stage) return; const placeholder = stage.querySelector('.size-14') || [...stage.querySelectorAll('div')].find((el) => el.children.length === 0 && el.offsetWidth >= 40 && el.offsetWidth <= 72); if (placeholder) setSize(placeholder, AVATAR_SIZE); stage.style.setProperty('width', Math.max(112, AVATAR_SIZE + 16) + 'px', 'important'); stage.style.setProperty('min-height', (AVATAR_SIZE + NAME_SPACE) + 'px', 'important'); } function enlargeFrame(frame) { // 元サイズは初回だけ記録する(適用後は offsetWidth が 96 になるため) if (!frame.dataset.museOriginalSize) { frame.dataset.museOriginalSize = String(frame.offsetWidth || 56); } const original = parseFloat(frame.dataset.museOriginalSize) || 56; const delta = AVATAR_SIZE - original; setSize(frame, AVATAR_SIZE); shiftAccessories(frame, delta); if (DEBUG && !frame.hasAttribute('data-muse-v4-applied')) { console.log('[Muse Avatar Enlarger v4] 上部フレームを拡大しました 元:', original + 'px', '→', AVATAR_SIZE + 'px', frame); } frame.setAttribute('data-muse-v4-applied', '1'); } function run() { cleanupOld(); enlargeStage(); document.querySelectorAll(FRAME_SELECTOR).forEach(enlargeFrame); } run(); // React が style を書き戻すことがあるため、監視+1秒ごとの再適用で維持する let queued = false; new MutationObserver(() => { if (queued) return; queued = true; requestAnimationFrame(() => { queued = false; run(); }); }).observe(document.documentElement, { childList: true, subtree: true }); setInterval(run, 1000); })();