From f7aee0723f8211d4ea2c431013a16792dbea3a50 Mon Sep 17 00:00:00 2001 From: John Smith Date: Sun, 3 May 2026 19:23:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=94=9F=E6=88=90=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E6=A0=B7=E5=BC=8F=E7=9A=84skill?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .agents/skills/blivechat-css-ref/SKILL.md | 81 ++++++ .../blivechat-css-ref/references/bubble.css | 269 ++++++++++++++++++ .../blivechat-css-ref/references/text.css | 241 ++++++++++++++++ frontend/src/views/StyleGenerator/Legacy.vue | 2 +- 4 files changed, 592 insertions(+), 1 deletion(-) create mode 100644 .agents/skills/blivechat-css-ref/SKILL.md create mode 100644 .agents/skills/blivechat-css-ref/references/bubble.css create mode 100644 .agents/skills/blivechat-css-ref/references/text.css diff --git a/.agents/skills/blivechat-css-ref/SKILL.md b/.agents/skills/blivechat-css-ref/SKILL.md new file mode 100644 index 0000000..0e781b2 --- /dev/null +++ b/.agents/skills/blivechat-css-ref/SKILL.md @@ -0,0 +1,81 @@ +--- +name: blivechat-css-ref +description: blivechat 自定义 CSS 参考。使用场景:用户提到 写/设计/生成/修改 一个 弹幕样式/CSS;排查弹幕样式不生效等问题。 +license: MIT +metadata: + author: xfgryujk +--- + +# blivechat 自定义 CSS 参考 + +blivechat 软件获取 bilibili 直播弹幕并以 HTML 形式在 OBS 中嵌入显示。默认样式模仿 YouTube,但可通过自定义 CSS 修改。 + +## 输出 + +输出为一个 CSS 文件。 + +如果用户未指定输出路径,则询问保存位置。推荐 `data/custom_public/preset.css`,因为在 blivechat 设置中启用 *导入服务器预设 CSS* 即可自动导入该文件。 + +**输出必须包含以下内容:** +```css +/* (必需)透明背景 */ +body, +yt-live-chat-renderer, +yt-live-chat-ticker-renderer, +yt-live-chat-author-chip #author-name { + background-color: transparent; +} + +/* (必需)隐藏滚动条 */ +body, +yt-live-chat-item-list-renderer #item-scroller { + overflow: hidden; +} +``` + +## 参考文件 + +- DOM 结构源码:`frontend/src/components/ChatRenderer/index.vue` +- 内置 YouTube 样式:`frontend/src/assets/css/youtube/`——默认样式未被覆盖时可以参考 +- [聊天气泡风格 CSS 示例](references/bubble.css) +- [纯文字无消息背景 CSS 示例](references/text.css)——添加文字描边以提高对比度 + +## 常用模式 + +### 修复含有大表情的文本消息中头像和用户名没有垂直对齐的问题 + +大表情会把文本消息的高度撑大,导致头像和用户名没有垂直对齐。 + +修复方式1,指定顶端对齐: +```css +yt-live-chat-text-message-renderer #content:has(.emoji.blc-large-emoji) > * { + vertical-align: top; +} +``` + +修复方式2,大表情换行显示: +```css +yt-live-chat-text-message-renderer #message:has(.emoji.blc-large-emoji) { + display: block; +} +``` + +### 区分舰队等级 + +文本消息 `yt-live-chat-text-message-renderer` 和上舰消息 `yt-live-chat-membership-item-renderer` 带有 `blc-guard-level` 属性区分舰队等级。 + +**blc-guard-level 取值:** +- `0`:非舰队成员 +- `1`:总督 +- `2`:提督 +- `3`:舰长 + +### 区分付费消息金额档位 + +付费消息 `yt-live-chat-paid-message-renderer` 带有 `blc-price-level` 属性区分金额档位。其值从低到高为 `0`-`7`,`0` 代表免费礼物。 + +### 引用本地资源文件 + +如需引用本地资源,将文件放入 `data/custom_public/` 目录,通过绝对 URL `/custom_public/` 引用。例如 `data/custom_public/img/bg.png` 可通过 `/custom_public/img/bg.png` 引用。 + +禁止使用 `file:` 协议引用本地文件,这种方式不可移植到其他主机。 diff --git a/.agents/skills/blivechat-css-ref/references/bubble.css b/.agents/skills/blivechat-css-ref/references/bubble.css new file mode 100644 index 0000000..75408f0 --- /dev/null +++ b/.agents/skills/blivechat-css-ref/references/bubble.css @@ -0,0 +1,269 @@ +@import url("https://fonts.googleapis.com/css?family=Noto%20Sans%20SC"); + +yt-live-chat-renderer { + /* 基准尺寸,用于整体缩放 */ + --base-size: 1px; + --font-base-size: calc(1 * var(--base-size)); + + /* 没有首选字体时的备用字体 */ + --fallback-fonts: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "\5FAE \8F6F \96C5 \9ED1 ", SimHei, Arial, sans-serif; + + /* 头像 */ + --avatar-size: calc(40 * var(--base-size)); + + /* 时间 */ + --time-color: #999999; + --time-size: calc(18 * var(--font-base-size)); + --time-weight: 400; + + /* 用户名 - 普通、舰长、房管、主播 */ + --username-color: #cccccc; + --username-color-member: #0f9d58; + --username-color-moderator: #5e84f1; + --username-color-owner: #ffd600; + --username-size: calc(18 * var(--font-base-size)); + --username-weight: 700; + + /* 文本消息 */ + --text-content-color: #000000; + --text-content-size: calc(20 * var(--font-base-size)); + --text-content-weight: 700; + + /* 表情 */ + --emote-size: calc(24 * var(--font-base-size)); + --large-emote-size: calc(60 * var(--font-base-size)); + + /* 背景色 - 普通、舰长、房管、主播 */ + --text-msg-bg-color: #ffffff; + --text-msg-bg-color-member: #3ACD2E; + --text-msg-bg-color-moderator: #3CA0FB; + --text-msg-bg-color-owner: #F5D401; + + /* 付费、上舰消息 */ + --paid-msg-line-1-size: calc(22 * var(--font-base-size)); + --paid-msg-line-1-weight: 700; + --paid-msg-line-2-size: calc(20 * var(--font-base-size)); + --paid-msg-line-2-weight: 700; + --paid-msg-content-size: calc(20 * var(--font-base-size)); + --paid-msg-content-weight: 700; + --membership-msg-bg-color: var(--username-color-member); +} + +/* (必需)透明背景 */ +body, +yt-live-chat-renderer, +yt-live-chat-ticker-renderer, +yt-live-chat-author-chip #author-name { + background-color: transparent; +} + +/* (必需)隐藏滚动条 */ +body, +yt-live-chat-item-list-renderer #item-scroller { + overflow: hidden; +} + +/* 通用规则 */ +yt-live-chat-renderer * { + font-size: var(--font-size); + --line-height: calc(var(--font-size) * 1.2); + line-height: var(--line-height); +} + +/* 减少两侧边距 */ +yt-live-chat-text-message-renderer { + padding-inline: 4px; +} + +/* 头像 */ +yt-live-chat-item-list-renderer :is(#author-photo, #author-photo img) { + width: var(--avatar-size); + height: var(--avatar-size); + margin-right: 10px; +} + +/* 时间 */ +yt-live-chat-text-message-renderer #timestamp { + display: none; +} + +/* 用户名 */ +yt-live-chat-text-message-renderer #author-name { + + color: var(--username-color); + font-family: "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--username-size); + font-weight: var(--username-weight); +} + +yt-live-chat-text-message-renderer :is(#author-name, yt-live-chat-author-badge-renderer)[type="owner"] { + color: var(--username-color-owner); +} + +yt-live-chat-text-message-renderer :is(#author-name, yt-live-chat-author-badge-renderer)[type="moderator"] { + color: var(--username-color-moderator); +} + +yt-live-chat-text-message-renderer :is(#author-name, yt-live-chat-author-badge-renderer)[type="member"] { + color: var(--username-color-member); +} + +yt-live-chat-text-message-renderer yt-live-chat-author-badge-renderer :is(img, yt-icon) { + --font-size: var(--username-size); + width: var(--line-height); + height: var(--line-height); +} + +yt-live-chat-text-message-renderer yt-live-chat-author-chip { + margin-bottom: 5px; +} + +/* 文本消息 */ +yt-live-chat-text-message-renderer :is(#message, #message *) { + color: var(--text-content-color); + font-family: "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--text-content-size); + font-weight: var(--text-content-weight); +} + +yt-live-chat-text-message-renderer #message .emoji { + width: auto; + height: var(--emote-size); +} + +yt-live-chat-text-message-renderer #message .emoji.blc-large-emoji { + height: var(--large-emote-size); +} + +/* 气泡背景 */ +yt-live-chat-text-message-renderer #message { + display: block; + position: relative; + width: fit-content; + overflow: visible; + padding: calc(12 * var(--base-size)) calc(20 * var(--base-size)); + border-radius: calc(24 * var(--base-size)); +} + +/* 气泡旁边的三角形箭头 */ +yt-live-chat-text-message-renderer #message::before { + content: ""; + display: block; + position: absolute; + top: 0; + left: 0; + border: calc(8 * var(--base-size)) solid transparent; + border-left-width: calc(18 * var(--base-size)); + border-right: calc(18 * var(--base-size)) solid green; + transform: translate(-50%, -50%) rotate(35deg); +} + +/* 适配隐藏大表情背景 */ +yt-live-chat-text-message-renderer #message:has(.emoji.blc-large-emoji)::before { + content: none; +} + +yt-live-chat-text-message-renderer #message:has(.emoji.blc-large-emoji) { + padding: 0; +} + +/* 背景色 */ +yt-live-chat-text-message-renderer #message { + background-color: var(--text-msg-bg-color); +} + +yt-live-chat-text-message-renderer #message::before { + border-right-color: var(--text-msg-bg-color); +} + +yt-live-chat-text-message-renderer[author-type="owner"] #message { + background-color: var(--text-msg-bg-color-owner); +} + +yt-live-chat-text-message-renderer[author-type="owner"] #message::before { + border-right-color: var(--text-msg-bg-color-owner); +} + +yt-live-chat-text-message-renderer[author-type="moderator"] #message { + background-color: var(--text-msg-bg-color-moderator); +} + +yt-live-chat-text-message-renderer[author-type="moderator"] #message::before { + border-right-color: var(--text-msg-bg-color-moderator); +} + +yt-live-chat-text-message-renderer[author-type="member"] #message { + background-color: var(--text-msg-bg-color-member); +} + +yt-live-chat-text-message-renderer[author-type="member"] #message::before { + border-right-color: var(--text-msg-bg-color-member); +} + +/* 隐藏大表情背景 */ +yt-live-chat-text-message-renderer #message:has(.emoji.blc-large-emoji) { + background-color: transparent; +} + +/* 付费、上舰消息 */ +yt-live-chat-paid-message-renderer { + margin: 4px 0; +} + +yt-live-chat-paid-message-renderer :is(#author-name, #author-name *), +yt-live-chat-membership-item-renderer :is(#header-content-inner-column, #header-content-inner-column *) { + font-family: "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--paid-msg-line-1-size); + font-weight: var(--paid-msg-line-1-weight); +} + +yt-live-chat-membership-item-renderer yt-live-chat-author-badge-renderer :is(img, yt-icon) { + width: var(--line-height); + height: var(--line-height); +} + +yt-live-chat-paid-message-renderer :is(#purchase-amount, #purchase-amount *), +yt-live-chat-membership-item-renderer :is(#header-subtext, #header-subtext *) { + font-family: "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--paid-msg-line-2-size); + font-weight: var(--paid-msg-line-2-weight); +} + +yt-live-chat-paid-message-renderer :is(#content, #content *) { + font-family: "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--paid-msg-content-size); + font-weight: var(--paid-msg-content-weight); +} + +yt-live-chat-membership-item-renderer :is(#card, #header) { + background-color: var(--membership-msg-bg-color); + margin: 4px 0; +} + +/* SC固定栏 */ +yt-live-chat-ticker-renderer :is(#items, #content) { + height: unset; +} + +yt-live-chat-ticker-paid-message-item-renderer #author-photo img { + --font-size: var(--paid-msg-line-2-size); + width: var(--line-height); + height: var(--line-height); +} + +yt-live-chat-ticker-paid-message-item-renderer #text { + font-family: "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--paid-msg-line-2-size); + font-weight: var(--paid-msg-line-2-weight); +} + +/* 动画 */ +@keyframes anim { + 0% { opacity: 0; translate: calc(-16 * var(--base-size)); } + 100% { opacity: 1; translate: none; } +} + +yt-live-chat-item-list-renderer #items > * { + animation: anim 200ms; + animation-fill-mode: both; +} diff --git a/.agents/skills/blivechat-css-ref/references/text.css b/.agents/skills/blivechat-css-ref/references/text.css new file mode 100644 index 0000000..3f49176 --- /dev/null +++ b/.agents/skills/blivechat-css-ref/references/text.css @@ -0,0 +1,241 @@ +@import url("https://fonts.googleapis.com/css?family=Imprima"); +@import url("https://fonts.googleapis.com/css?family=Noto%20Sans%20SC"); + +yt-live-chat-renderer { + /* 基准尺寸,用于整体缩放 */ + --base-size: 1px; + --font-base-size: calc(1 * var(--base-size)); + + /* 没有首选字体时的备用字体 */ + --fallback-fonts: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "\5FAE \8F6F \96C5 \9ED1 ", SimHei, Arial, sans-serif; + + /* 头像 */ + --avatar-size: calc(24 * var(--base-size)); + + /* 时间 */ + --time-color: #999999; + --time-size: calc(20 * var(--font-base-size)); + --time-weight: 400; + + /* 用户名 - 普通、舰长、房管、主播 */ + --username-color: #cccccc; + --username-color-member: #0f9d58; + --username-color-moderator: #5e84f1; + --username-color-owner: #ffd600; + --username-size: calc(20 * var(--font-base-size)); + --username-weight: 700; + + /* 文本消息 */ + --text-content-color: #ffffff; + --text-content-size: calc(20 * var(--font-base-size)); + --text-content-weight: 700; + + /* 表情 */ + --emote-size: calc(24 * var(--font-base-size)); + --large-emote-size: calc(40 * var(--font-base-size)); + + /* 描边 */ + --outline-color: #000000; + + /* 背景色 - 普通、舰长、房管、主播 */ + --text-msg-bg-color: rgba(204, 204, 204, 0); + --text-msg-bg-color-member: rgba(15, 157, 88, 0); + --text-msg-bg-color-moderator: rgba(94, 132, 241, 0); + --text-msg-bg-color-owner: rgba(255, 214, 0, 0); + + /* 付费、上舰消息 */ + --paid-msg-line-1-color: #ffffff; + --paid-msg-line-1-size: calc(22 * var(--font-base-size)); + --paid-msg-line-1-weight: 700; + --paid-msg-line-2-color: #ffffff; + --paid-msg-line-2-size: calc(20 * var(--font-base-size)); + --paid-msg-line-2-weight: 700; + --paid-msg-content-color: #ffffff; + --paid-msg-content-size: calc(20 * var(--font-base-size)); + --paid-msg-content-weight: 700; + --membership-msg-bg-color: var(--username-color-member); +} + +/* (必需)透明背景 */ +body, +yt-live-chat-renderer, +yt-live-chat-ticker-renderer, +yt-live-chat-author-chip #author-name { + background-color: transparent; +} + +/* (必需)隐藏滚动条 */ +body, +yt-live-chat-item-list-renderer #item-scroller { + overflow: hidden; +} + +/* 通用规则 */ +yt-live-chat-renderer * { + font-size: var(--font-size); + --line-height: calc(var(--font-size) * 1.2); + line-height: var(--line-height); +} + +/* 减少两侧边距 */ +yt-live-chat-text-message-renderer { + padding-inline: 4px 4px; +} + +/* 描边 */ +yt-live-chat-renderer * { + text-shadow: -2px -2px var(--outline-color), -2px -1px var(--outline-color), -2px 0px var(--outline-color), -2px 1px var(--outline-color), -2px 2px var(--outline-color), -1px -2px var(--outline-color), -1px -1px var(--outline-color), -1px 0px var(--outline-color), -1px 1px var(--outline-color), -1px 2px var(--outline-color), 0px -2px var(--outline-color), 0px -1px var(--outline-color), 0px 0px var(--outline-color), 0px 1px var(--outline-color), 0px 2px var(--outline-color), 1px -2px var(--outline-color), 1px -1px var(--outline-color), 1px 0px var(--outline-color), 1px 1px var(--outline-color), 1px 2px var(--outline-color), 2px -2px var(--outline-color), 2px -1px var(--outline-color), 2px 0px var(--outline-color), 2px 1px var(--outline-color), 2px 2px var(--outline-color); +} + +/* 头像 */ +yt-live-chat-item-list-renderer :is(#author-photo, #author-photo img) { + width: var(--avatar-size); + height: var(--avatar-size); + margin-right: 10px; +} + +/* 时间 */ +yt-live-chat-text-message-renderer #timestamp { + display: none; +} + +/* 用户名 */ +yt-live-chat-text-message-renderer #author-name { + + color: var(--username-color); + font-family: "Imprima", "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--username-size); + font-weight: var(--username-weight); +} + +yt-live-chat-text-message-renderer :is(#author-name, yt-live-chat-author-badge-renderer)[type="owner"] { + color: var(--username-color-owner); +} + +yt-live-chat-text-message-renderer :is(#author-name, yt-live-chat-author-badge-renderer)[type="moderator"] { + color: var(--username-color-moderator); +} + +yt-live-chat-text-message-renderer :is(#author-name, yt-live-chat-author-badge-renderer)[type="member"] { + color: var(--username-color-member); +} + +yt-live-chat-text-message-renderer yt-live-chat-author-badge-renderer :is(img, yt-icon) { + --font-size: var(--username-size); + width: var(--line-height); + height: var(--line-height); +} + +/* 显示冒号 */ +yt-live-chat-text-message-renderer #author-name::after { + content: ":"; + margin-left: 2px; +} + +/* 文本消息 */ +yt-live-chat-text-message-renderer :is(#message, #message *) { + color: var(--text-content-color); + font-family: "Imprima", "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--text-content-size); + font-weight: var(--text-content-weight); +} + +yt-live-chat-text-message-renderer #message .emoji { + width: auto; + height: var(--emote-size); +} + +yt-live-chat-text-message-renderer #message .emoji.blc-large-emoji { + height: var(--large-emote-size); +} + +yt-live-chat-text-message-renderer #content:has(.emoji.blc-large-emoji) > * { + vertical-align: top; +} + +/* 背景色 */ +yt-live-chat-text-message-renderer { + background-color: var(--text-msg-bg-color); +} + +yt-live-chat-text-message-renderer[author-type="owner"] { + background-color: var(--text-msg-bg-color-owner); +} + +yt-live-chat-text-message-renderer[author-type="moderator"] { + background-color: var(--text-msg-bg-color-moderator); +} + +yt-live-chat-text-message-renderer[author-type="member"] { + background-color: var(--text-msg-bg-color-member); +} + +/* 付费、上舰消息 */ +yt-live-chat-paid-message-renderer { + margin: 4px 0; +} + +yt-live-chat-paid-message-renderer :is(#author-name, #author-name *), +yt-live-chat-membership-item-renderer :is(#header-content-inner-column, #header-content-inner-column *) { + font-family: "Imprima", "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--paid-msg-line-1-size); + font-weight: var(--paid-msg-line-1-weight); +} + +yt-live-chat-membership-item-renderer yt-live-chat-author-badge-renderer :is(img, yt-icon) { + width: var(--line-height); + height: var(--line-height); +} + +yt-live-chat-paid-message-renderer :is(#purchase-amount, #purchase-amount *), +yt-live-chat-membership-item-renderer :is(#header-subtext, #header-subtext *) { + font-family: "Imprima", "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--paid-msg-line-2-size); + font-weight: var(--paid-msg-line-2-weight); +} + +yt-live-chat-paid-message-renderer :is(#content, #content *) { + font-family: "Imprima", "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--paid-msg-content-size); + font-weight: var(--paid-msg-content-weight); +} + +yt-live-chat-membership-item-renderer :is(#card, #header) { + background-color: var(--membership-msg-bg-color); + margin: 4px 0; +} + +/* SC固定栏 */ +yt-live-chat-ticker-renderer :is(#items, #content) { + height: unset; +} + +yt-live-chat-ticker-paid-message-item-renderer #author-photo img { + --font-size: var(--paid-msg-line-2-size); + width: var(--line-height); + height: var(--line-height); +} + +yt-live-chat-ticker-paid-message-item-renderer #text { + font-family: "Imprima", "Noto Sans SC", var(--fallback-fonts); + --font-size: var(--paid-msg-line-2-size); + font-weight: var(--paid-msg-line-2-weight); +} + +yt-live-chat-paid-message-renderer :is(#author-name, #author-name *), +yt-live-chat-membership-item-renderer :is(#header-content-inner-column, #header-content-inner-column *) { + color: var(--paid-msg-line-1-color); +} + +yt-live-chat-paid-message-renderer :is(#purchase-amount, #purchase-amount *), +yt-live-chat-membership-item-renderer :is(#header-subtext, #header-subtext *) { + color: var(--paid-msg-line-2-color); +} + +yt-live-chat-paid-message-renderer :is(#content, #content *) { + color: var(--paid-msg-content-color); +} + +yt-live-chat-ticker-paid-message-item-renderer #content { + color: var(--paid-msg-line-2-color) !important; +} diff --git a/frontend/src/views/StyleGenerator/Legacy.vue b/frontend/src/views/StyleGenerator/Legacy.vue index 70a0c83..df83949 100644 --- a/frontend/src/views/StyleGenerator/Legacy.vue +++ b/frontend/src/views/StyleGenerator/Legacy.vue @@ -603,7 +603,7 @@ ${!this.form.messageOnNewLine ? '' : `yt-live-chat-text-message-renderer #messag overflow: visible; }`} -yt-live-chat-text-message-renderer #message:has(.emoji.blc-large-emoji) { +yt-live-chat-text-message-renderer #content:has(.emoji.blc-large-emoji) > * { vertical-align: top; }` },