diff --git a/.codex/skills/create-cc-web-theme/SKILL.md b/.codex/skills/create-cc-web-theme/SKILL.md new file mode 100644 index 0000000..207bb23 --- /dev/null +++ b/.codex/skills/create-cc-web-theme/SKILL.md @@ -0,0 +1,139 @@ +--- +name: create-cc-web-theme +description: 为 cc-web 创建、复刻、重做或审计视觉主题,从参考图、概念图、背景图、图标板或素材板完成需求澄清、源素材归档、主题隔离、可复现切图、CSS/DOM 接入、响应式、回归和真实浏览器视觉验收。用户提到新建主题、换肤、复刻设计稿、主题高保真、主题对比、切图、图标重做、欢迎卡、输入框装饰框、消息气泡磨砂、视觉错位或主题返工时使用。 +--- + +# 创建 cc-web 主题 + +把参考设计转成一个独立、可切换、可维护并经过真实浏览器验收的 cc-web 主题。保留设计证据和生成链路,避免只留下无法继续扩展的最终切片。 + +## 按需读取参考 + +- 开始定位主题系统前,读取 [cc-web-theme-architecture.md](references/cc-web-theme-architecture.md)。 +- 收到背景、图标板、边框板或概念图时,读取 [asset-workflow.md](references/asset-workflow.md)。 +- 遇到“不像设计图”“改了没变化”“边框/图标/透明度/居中反复不对”时,读取 [lessons-learned.md](references/lessons-learned.md)。 +- 准备声明完成前,完整读取并执行 [acceptance-checklist.md](references/acceptance-checklist.md)。 + +## 遵守硬约束 + +1. 为新主题创建新的稳定主题 ID 和独立资产目录。除非用户明确要求,禁止覆盖、重命名或删除现有主题。 +2. 修改前检查工作树与相关文件差异。保留用户和其他任务的未提交改动,不格式化或重排无关大文件。 +3. 先归档所有源概念图、素材板和背景,再生成派生资产。保留裁剪脚本、坐标、manifest 和来源哈希。 +4. 把参考图当作构图与层级契约,不只提取颜色和“氛围”。先量化,再编码。 +5. 只使用本地主题资产。禁止让产品运行时依赖参考站点、临时附件 URL 或远程图片。 +6. 同步维护静态首屏 DOM 与动态渲染 DOM。动态项目名、Agent、会话标题等内容禁止写死在静态模板中。 +7. 只修改用户指出的层级。用户说“气泡背景”时,不得顺手重做所有卡片、工具层或布局。 +8. 自动化通过不等于视觉完成。没有真实浏览器对照、动态状态检查和多视口验收时,不得声明完成。 +9. 不删除源图、概念图、素材板、切片或提取脚本;后续功能可能需要重新切片。 +10. 需要重启 cc-web 时,先按仓库 `AGENTS.md` 检查其他运行中会话;不满足条件时不重启。 + +## 执行工作流 + +### 1. 固定需求和完成标准 + +明确并记录: + +- 新建、复刻、扩展还是修复主题。 +- 主题稳定 ID、显示名、是否与旧主题并存、默认主题是否变化。 +- 参考图、背景图、图标板、边框板、字体和其他输入素材的角色。 +- 用户要求保留的既有视觉与明确禁止改动的区域。 +- 参考图原始视口、桌面目标视口和移动端目标视口。 +- 必须覆盖的动态状态:空会话、长消息、多行输入、工具调用、展开菜单、运行/停止、弹层和窄屏。 + +在任务资料中建立资产表和验收清单。输入素材含义不明确且会影响构图或切片时,先向用户确认。 + +### 2. 建立代码与改动基线 + +优先使用 `codebase-memory-mcp`: + +1. 调用 `list_projects` 和 `index_status(project="home-cc-web")`。 +2. 使用 `search_graph` / `search_code` 定位主题注册、应用、静态 bootstrap、动态 welcome 和回归入口。 +3. 需要调用关系时使用 `trace_path`,需要源码时先取得 `qualified_name` 再调用 `get_code_snippet`。 +4. 最后使用 `rg` 和 `git diff` 校验文本、行号与未索引资源。 + +记录主题相关脏文件、既有主题 ID、缓存版本、共享选择器和任务开始时的资产清单。只在明确边界内修改。 + +### 3. 把参考图拆成可验证规格 + +先输出“参考区域 → 实际 DOM → 资产 → CSS 责任”的映射,再实施。 + +至少量化: + +- 侧栏、顶栏、消息区、输入区的比例和基线。 +- 主视觉安全区、文字阅读区和背景裁切/遮罩策略。 +- 面板层级、透明度感知、边线宽度、阴影和切角使用范围。 +- 每类控件的容器尺寸、图标视觉主体、间距和光学中心。 +- 固定尺寸与动态高度组件的区别。 +- 静态空页面和有内容页面的布局差异。 + +先处理背景与大布局,再处理容器层级、边框、图标和微交互。禁止从局部颜色微调开始掩盖结构偏差。 + +### 4. 建立可复现资产链路 + +把源素材复制到当前主题任务的 `references/source-assets/`,不要只引用会话附件路径。为每个派生资产保存: + +- 源文件名和哈希。 +- 源裁剪框、规格或素材板单元格。 +- 输出尺寸、格式和用途。 +- alpha/颜色分离方法和必要的光学校正。 +- 生成脚本与 manifest。 + +按用途选择实现: + +- 背景保留构图和清晰度,遮罩只服务可读性。 +- 主交互小图标优先使用干净 mask 或对应尺寸切片;多色状态、头像和装饰图标保留原色。 +- 非对称图标按 alpha 加权重心校正,不按透明画布机械居中。 +- 固定尺寸框可使用完整切片;动态高度框优先使用 `border-image`/九宫格或拆分稳定边角,禁止把固定比例整图放在伪元素上随内容拉伸。 + +具体方法见 [asset-workflow.md](references/asset-workflow.md)。 + +### 5. 分层、隔离地接入主题 + +按以下顺序实现: + +1. 在 `THEME_OPTIONS` 新增主题元数据,保持单一数据源。 +2. 检查首屏 bootstrap、`normalizeTheme()`、`applyTheme()` 和本地持久化是否接受新 ID。 +3. 在 `html[data-theme='']` 变量块中先定义语义 token。 +4. 把新暗色主题加入确实需要复用的共享 completion selector。 +5. 把高风险视觉放在文件后部的主题专属组件层,所有选择器都限定主题 ID。 +6. 把资产放入 `public/assets/themes//`,避免根目录同名覆盖。 +7. 同步静态 `index.html` 和动态构建函数中的 welcome/装饰 DOM。 +8. 检查真实 DOM 内原生文字、SVG、图片和主题伪元素,防止加号、头像、图标或边框重复。 +9. 更新 CSS/JS cache bust,并同步回归契约。 + +不要为了视觉方便复制第二套业务逻辑、主题列表或交互组件。 + +### 6. 用真实浏览器形成短反馈环 + +先按参考图原始尺寸验收,再检查常规桌面和窄屏。每轮只解决一个明确层级,并记录修改前后证据。 + +遇到异常时按顺序排查: + +1. 浏览器是否实际加载了最新缓存版本和资源。 +2. 选择器是否命中真实 DOM,伪元素或原生子节点是否重复。 +3. computed style 的最终来源和 specificity,特别检查 `:is()` 与旧 `!important`。 +4. 外层看似透明时,内层工具块、标题层或伪元素是否仍不透明。 +5. 动态高度、文字换行、菜单展开和运行状态是否改变真实尺寸。 +6. 几何中心、文字基线和图标 alpha 重心是否一致。 + +优先测量,不盲调数值。把“看着偏”转换为中心差、边距、主体 bbox、computed background 或溢出量。 + +### 7. 完成工程与视觉验收 + +执行 [acceptance-checklist.md](references/acceptance-checklist.md) 的全部强制项,至少包含: + +- JS 语法检查、主题专项回归、相关旧主题回归、全量回归和 `git diff --check`。 +- 本地资产存在性、格式、尺寸、hash/manifest 与 HTTP 200。 +- 参考视口、常规桌面和窄屏的真实浏览器检查。 +- 空页面、长内容、多行输入、菜单、工具块、按钮状态和动态文案检查。 +- 与参考图逐组件对照,确认没有多余边框、重复图标、视觉实心层或明显错位。 + +最后报告实际视觉证据、验证命令和保留的源资产/脚本路径。测试失败、浏览器不可用或视觉证据不足时明确说明,保持任务未完成状态。 + +## 交付要求 + +- 列出新增主题 ID、资产目录、源资产归档和提取脚本。 +- 列出修改过的主题链路文件与隔离边界。 +- 给出真实浏览器实测结果,不只写“回归通过”。 +- 说明仍未覆盖的视口、状态或素材限制。 +- 保留所有主题概念图、素材板、切片、manifest 和生成脚本。 diff --git a/.codex/skills/create-cc-web-theme/agents/openai.yaml b/.codex/skills/create-cc-web-theme/agents/openai.yaml new file mode 100644 index 0000000..07015fc --- /dev/null +++ b/.codex/skills/create-cc-web-theme/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "创建 cc-web 主题" + short_description: "从参考设计图到本地切片、主题隔离实现与真实浏览器视觉验收" + default_prompt: "使用 $create-cc-web-theme 根据参考图创建一个独立、可切换并经过真实浏览器验收的 cc-web 主题。" diff --git a/.codex/skills/create-cc-web-theme/references/acceptance-checklist.md b/.codex/skills/create-cc-web-theme/references/acceptance-checklist.md new file mode 100644 index 0000000..3115277 --- /dev/null +++ b/.codex/skills/create-cc-web-theme/references/acceptance-checklist.md @@ -0,0 +1,127 @@ +# cc-web 主题完成验收清单 + +把本清单作为完成门禁。任一强制项未验证时,保持任务未完成并说明原因。 + +## 1. 范围与隔离 + +- [ ] 新主题使用独立稳定 ID,未覆盖现有主题。 +- [ ] `THEME_OPTIONS`、bootstrap、持久化和 picker 的语义一致。 +- [ ] 现有主题仍可选择/迁移,并通过其专项回归。 +- [ ] 所有专属 selector 都限定新主题 ID。 +- [ ] 未修改主题无关业务逻辑、交互或大文件格式。 +- [ ] 已复核相关脏文件,没有覆盖用户或并行任务改动。 + +## 2. 源素材与派生资产 + +- [ ] 概念图、完整参考、背景和素材板已归档到任务目录。 +- [ ] 归档文件与原始输入 hash 已核对。 +- [ ] 生成脚本和 manifest 已保留且可重放。 +- [ ] 派生资产记录源文件、裁剪框、规格、尺寸和用途。 +- [ ] 透明 PNG 无棋盘格、黑边或被裁掉的尖角。 +- [ ] 图标 alpha 主体尺寸和光学中心符合控件层级。 +- [ ] 所有运行时资产位于 `public/assets/themes//`。 +- [ ] 主题实现与 manifest 不包含远程图片 URL。 + +## 3. DOM 与组件实现 + +- [ ] 静态 `index.html` 与动态 welcome 构建函数结构同步。 +- [ ] 项目名、Agent、会话标题等动态内容没有写死。 +- [ ] 新主题图标未与原生文字、SVG、图片或旧伪元素重叠。 +- [ ] 新会话加号、下拉、操作菜单和设置入口仍可见、可点击。 +- [ ] 菜单展开不被父级 overflow 裁切。 +- [ ] 固定框与动态尺寸框使用了合适的切片策略。 +- [ ] 输入框单行、多行、聚焦、拖拽和特殊模式都没有双边框或错位。 +- [ ] 工具块、协作卡、弹层和消息嵌套层没有意外不透明底色。 +- [ ] `prefers-reduced-motion` 能关闭主题动画/过渡。 + +## 4. 视觉对照 + +### 参考视口 + +- [ ] 在参考图原始尺寸或同等宽高比下截图/检查。 +- [ ] 背景主体、人物、纹理和安全区与参考构图一致。 +- [ ] 侧栏、顶栏、消息区和输入区比例无明显偏差。 +- [ ] 面板层级清楚,没有全页面卡片化或遮罩过暗。 +- [ ] 边框轻重、切角范围和阴影符合参考层级。 +- [ ] 主文字可读,用户指定的颜色与对比度已满足。 +- [ ] 没有重复图标、莫名边框、虚线、色块或“一坨”叠层。 + +### 几何证据 + +- [ ] 主卡片中心与实际聊天画布中心误差可接受。 +- [ ] 图标以 alpha 主体/光学重心居中,不只看画布。 +- [ ] 文字与图标基线一致。 +- [ ] 欢迎卡、输入框和菜单没有横向溢出或裁切。 +- [ ] 记录关键 bbox、中心差、间距或 computed style。 + +### 透明与磨砂 + +- [ ] 背景纹理在设计要求透明的层中实际可见。 +- [ ] 外层气泡与内层工具块分别检查背景。 +- [ ] blur 没有把背景细节抹成实心色块。 +- [ ] computed style 的最终 background/backdrop-filter 来自预期 selector。 + +## 5. 动态状态 + +- [ ] 新建空会话欢迎页。 +- [ ] 当前项目名称/其他动态文案刷新正确。 +- [ ] 短消息、长消息、代码块和工具调用。 +- [ ] 用户/助手/系统/跨会话气泡。 +- [ ] 单行与多行输入。 +- [ ] 附件、笔记、队列、发送和停止状态。 +- [ ] 会话 hover、active、操作菜单展开。 +- [ ] 设置页、主题选择器、弹层和移动端侧栏。 + +## 6. 多视口 + +至少检查: + +- [ ] 参考设计原始视口,例如 1672×941。 +- [ ] 常规桌面,例如 1440×900。 +- [ ] 窄屏,例如 500px 宽。 +- [ ] 移动端,例如 390×844。 +- [ ] 各视口横向溢出为 0 或有明确设计原因。 +- [ ] 背景定位、侧栏宽度、输入框和欢迎卡在断点处连续。 + +## 7. 自动化与静态检查 + +根据实际主题 target 调整 ``: + +```bash +timeout 60s node --check public/app.js +timeout 60s node --check scripts/regression.js +timeout 60s npm run regression -- --target -theme +timeout 60s npm run regression -- --target -theme +timeout 60s npm run regression +git diff --check +``` + +- [ ] 新主题专项回归通过。 +- [ ] 相关旧主题专项回归通过。 +- [ ] 全量回归通过。 +- [ ] JS 语法检查通过。 +- [ ] `git diff --check` 通过。 +- [ ] 回归覆盖注册、隔离、静态/动态 DOM、资产、响应式、对比度、reduced-motion 和 cache bust。 + +## 8. 在线与浏览器校验 + +- [ ] 先用 `curl http://127.0.0.1:/` 确认本地服务。 +- [ ] 如远程浏览器不能访问 localhost,使用 `hostname -I` 中的 `11.144.144.*` 地址。 +- [ ] CSS、JS 和每个新增资产请求返回 200。 +- [ ] 浏览器实际加载的 cache-busted URL 是最新版本。 +- [ ] 使用 Firefox/Playwright/Selenium 读取关键 computed style 和几何值。 +- [ ] 浏览器截图或实测记录已写入任务进度。 + +不要仅因浏览器访问 `127.0.0.1` 失败就判断服务未启动。 + +## 9. 交付与保留 + +- [ ] 列出新主题 ID、显示名和资产目录。 +- [ ] 列出修改文件和未触碰的旧主题边界。 +- [ ] 列出源素材归档、manifest 和提取脚本路径。 +- [ ] 报告真实浏览器结果和多视口数据。 +- [ ] 报告专项/全量回归结果。 +- [ ] 说明任何未验收状态或环境限制。 +- [ ] 未删除概念图、素材板、切片或生成脚本。 + +只有工程检查、真实浏览器视觉和参考图对照全部满足后,才能把主题标记为完成。 diff --git a/.codex/skills/create-cc-web-theme/references/asset-workflow.md b/.codex/skills/create-cc-web-theme/references/asset-workflow.md new file mode 100644 index 0000000..6f0db29 --- /dev/null +++ b/.codex/skills/create-cc-web-theme/references/asset-workflow.md @@ -0,0 +1,172 @@ +# 主题素材归档与切片工作流 + +## 目录 + +1. 建立素材台账 +2. 归档源素材 +3. 分析构图与安全区 +4. 提取背景、边框、图标和纹理 +5. 处理动态组件装饰框 +6. 保存 manifest 和生成脚本 +7. 资产质量门禁 + +## 1. 建立素材台账 + +收到素材后立即记录: + +| 字段 | 说明 | +|---|---| +| 角色 | 完整参考、背景、图标板、边框板、欢迎卡、纹理或字体 | +| 原始路径 | 会话附件或用户提供位置 | +| 归档路径 | 当前主题任务的 `references/source-assets/` | +| 尺寸/格式 | 像素尺寸、RGB/RGBA、PNG/WebP/JPEG 等 | +| SHA-256 | 防止后续误换源图 | +| 是否含 alpha | 决定是否需要背景分离 | +| 允许用途 | 背景、切片源、对照图或仅参考 | + +不要把完整参考图直接当产品背景,也不要把带标题、尺寸标签和卡片底的图标板当 CSS sprite。 + +## 2. 归档源素材 + +优先归档到: + +```text +.trellis/tasks/-/references/source-assets/ +``` + +保留原始文件名或建立清晰映射。归档后核对源附件与归档文件 hash 一致。后续脚本只读取归档路径,避免依赖可能清理的会话附件。 + +禁止删除: + +- 完整概念图。 +- 背景源图。 +- 图标/边框/欢迎卡素材板。 +- 视觉对照截图。 +- 提取脚本和 manifest。 + +## 3. 分析构图与安全区 + +按原始像素尺寸记录: + +- 主视觉主体 bbox。 +- 适合侧栏和正文的低干扰区域。 +- 不能被消息、遮罩或输入区压住的高权重区域。 +- 顶部、底部和移动端裁切风险。 +- 参考图中的真实视口与组件坐标。 + +遮罩的目标是稳定文字对比,不是继续压暗整张背景。先让背景主体可见,再由局部面板解决可读性。 + +## 4. 提取背景、边框、图标和纹理 + +### 背景 + +- 优先保留用户提供的原图和构图比例。 +- 使用 WebP/PNG/JPEG 等项目已支持格式。 +- 记录 `background-size`、`background-position` 和各视口裁切策略。 +- 不对主视觉背景使用 blur,除非设计稿明确如此。 + +### 边框 + +- 从参考图提取时保留角线、短高光和必要装饰,清除烘焙背景与棋盘格。 +- 先确认边框属于固定尺寸还是动态尺寸组件。 +- 固定尺寸按钮可使用完整透明 PNG。 +- 动态高度输入框、长工具块或可伸缩卡片使用 `border-image`/九宫格,或拆成角、边和独立装饰。 +- 不把固定宽高比整框放在 `::before` 后强行覆盖动态内容。 + +### 图标 + +区分四个概念: + +1. 设计目标尺寸。 +2. 素材板中的物理像素尺寸。 +3. 输出透明画布尺寸。 +4. 实际 alpha 主体 bbox。 + +按控件用途选择源规格,不要所有图标统一从最大档裁出后再缩到同一个 CSS 尺寸。 + +- 小动作按钮:优先干净单色 mask,主体通常比容器小。 +- 主操作按钮:使用更高规格源图,允许更大视觉主体。 +- 多色状态、头像和主题装饰:保留原色,单独处理尺寸。 +- 非方形图标:保持比例并放入统一画布,不拉伸。 +- 非对称图标:按 alpha 加权重心校正光学中心。 + +alpha 加权中心: + +```text +cx = sum(x * alpha) / sum(alpha) +cy = sum(y * alpha) / sum(alpha) +offset = canvas_center - (cx, cy) +``` + +### RGB 素材板分离 alpha + +RGB WebP 常含有损压缩噪点,不能只用单一亮度阈值。推荐: + +1. 按主体外扩 2–4px 裁剪。 +2. 从边缘 flood-fill 识别与暗背景相连区域。 +3. 结合亮度、色相和局部差值识别金色/浅色/状态色。 +4. 去除小连通域噪点。 +5. 对 alpha 轻微羽化,避免黑边。 +6. 在深色、浅色和半透明背景上人工复核。 + +阈值必须针对当前素材板调试,不跨主题硬编码。 + +## 5. 处理动态组件装饰框 + +### 先问三个问题 + +1. 组件宽高是否随内容变化? +2. 哪些区域可以拉伸,哪些角/徽记必须保持比例? +3. 聚焦、拖拽、笔记、运行等状态是否改变 border 或尺寸? + +### 推荐选择 + +| 场景 | 推荐 | +|---|---| +| 固定 48px 按钮 | 完整透明框图或 mask | +| 宽度变化、高度固定 | 水平三段切片或 `border-image` | +| 宽高都变化 | 九宫格 `border-image` | +| 底部中心徽记不能拉伸 | 框体九宫格 + 独立徽记,或通过不拉伸 slice 保留 | +| 装饰只是短角线 | CSS border + 小伪元素,不加载整张框 | + +测试最短、常规和最长内容。只验证单行输入不能证明动态框正确。 + +## 6. 保存 manifest 和生成脚本 + +每个派生资产至少记录: + +```json +{ + "name": "send", + "source": "icon-sheet.webp", + "source_sha256": "...", + "source_box": [x, y, width, height], + "variant": "24px", + "detected_box": [x, y, width, height], + "output": "icons/send.png", + "size": [32, 32], + "usage": "composer primary action" +} +``` + +生成脚本应: + +- 使用项目已有依赖,避免为一次切图引入重量级包。 +- 只读取归档源素材。 +- 可重复运行并稳定覆盖派生资产。 +- 写出 manifest,失败时指出具体资产。 +- 用中文注释说明当前素材板特有的阈值、区域和校正。 + +Wasteland 案例脚本位于 `.trellis/tasks/07-17-gilded-wasteland-theme/research/extract_reference_chrome.py`,只可作为方法参考,不要直接复用其坐标和颜色阈值。 + +## 7. 资产质量门禁 + +- 文件格式、尺寸和 alpha 通道符合用途。 +- 背景 hash 与归档源一致,或记录过转换原因。 +- manifest 与实际文件一一对应,没有遗漏或多余派生图。 +- 透明图在深/浅/半透明背景上无黑边和棋盘格。 +- 尖角、纸飞机尾部、气泡尾巴和状态色未被裁掉。 +- 图标实际主体尺寸符合控件层级,不以画布尺寸代替可见尺寸。 +- 光学中心误差可解释并在按钮中实测。 +- 浏览器请求所有资产返回 200,MIME 正确。 +- 源素材、manifest 和提取脚本仍然存在。 diff --git a/.codex/skills/create-cc-web-theme/references/cc-web-theme-architecture.md b/.codex/skills/create-cc-web-theme/references/cc-web-theme-architecture.md new file mode 100644 index 0000000..1ee60f4 --- /dev/null +++ b/.codex/skills/create-cc-web-theme/references/cc-web-theme-architecture.md @@ -0,0 +1,158 @@ +# cc-web 主题架构与修改边界 + +## 目录 + +1. 代码定位顺序 +2. 主题运行链路 +3. CSS 分层 +4. DOM 双路径 +5. 资产与回归 +6. 脏工作树与服务约束 + +## 1. 代码定位顺序 + +不要依赖固定行号。按符号和稳定文本定位: + +1. `public/app.js` + - `THEME_OPTIONS` + - `normalizeTheme` + - `applyTheme` + - `buildThemePickerHtml` / `mountThemePicker` + - `buildWelcomeMarkup` +2. `public/index.html` + - CSS 加载前的主题 bootstrap + - 静态 welcome DOM + - CSS/JS cache-busting query +3. `public/style.css` + - `html[data-theme='']` 语义变量 + - 共享暗色 `:is(...)` completion selectors + - 文件后部的主题专属组件层 + - 响应式与 `prefers-reduced-motion` +4. `scripts/regression.js` + - `assertFrontendThemeContract` + - `--target -theme` + - 全量回归入口 +5. `public/assets/themes//` + - background、frames、icons、textures、manifest + +先用 codebase-memory 找符号和调用关系,再用 `rg` 核对资源文本与最终位置。 + +## 2. 主题运行链路 + +```text +THEME_OPTIONS + ├── 设置页主题候选 / label / desc / swatches + ├── normalizeTheme() 判断持久化值是否合法 + └── applyTheme() + ├── document.documentElement.dataset.theme + └── localStorage['cc-web-theme'] + +index.html bootstrap + └── CSS 加载前写入 data-theme,避免首屏闪烁 + +html[data-theme=''] + └── 语义变量 → 共享组件 → 主题专属组件层 +``` + +主题列表只维护一份。不要在设置页或其他弹层硬编码第二份主题候选。 + +### 新主题 ID + +- 使用稳定、小写、可长期保留的 ID。 +- 新主题默认新建 ID;不要借用隐藏主题、历史主题或另一个风格的 ID。 +- 保留旧主题用于对比时,不修改其 label、资产和 selector。 +- 如需迁移旧 ID,明确写出 `旧值 → 新值`,并增加回归断言。 + +## 3. CSS 分层 + +按以下层次组织: + +1. **语义变量层**:背景、文字、边线、强调色、面板色。 +2. **共享 completion 层**:只放多个暗色主题确实共用的组件补齐。 +3. **基础 UI 层**:不因单个主题改变业务布局或交互。 +4. **主题专属层**:背景、边框、图标、welcome、特殊响应式。 + +专属层应放在共享规则之后,并限定 `html[data-theme='']`。当后置规则仍无效时,检查 specificity,而不是继续追加更宽泛的选择器。 + +### `:is()` 风险 + +`:is()` 的 specificity 取参数中最高值。共享规则例如: + +```css +:is( + html[data-theme='a'] .msg.assistant .msg-bubble, + html[data-theme='b'] .msg.system .msg-bubble[data-tone='info'] +) { ... } +``` + +可能比后面的普通主题规则更强。出现“backdrop-filter 变了但 background 没变”时,必须查看 computed style 的规则来源;必要时使用同级 specificity 或只对冲突声明使用精确 `!important`。 + +## 4. DOM 双路径 + +welcome 页面同时存在: + +- `public/index.html` 的静态首屏结构。 +- `public/app.js` 的 `buildWelcomeMarkup()` 动态结构。 + +新增图层、class、无障碍属性、文案节点或图片时必须同步两处。 + +动态数据必须由 JS 统一填充,例如: + +- 当前项目名称来自 `cwd`。 +- 当前 Agent 名称来自运行时状态。 +- 当前会话标题来自 snapshot。 + +静态 HTML 只保留可定位的空节点或不依赖运行时的数据。回归必须断言静态模板没有写死动态名称。 + +### 重复视觉来源 + +实现主题图标前检查实际 DOM: + +- 文本 `+`、`▾`、`…`。 +- 内联 SVG。 +- `` 头像。 +- 基础主题已有的 `::before` / `::after`。 +- 新主题 background/mask。 + +同一语义只保留一个可见来源,并只在当前主题下隐藏旧来源。 + +## 5. 资产与回归 + +推荐目录: + +```text +public/assets/themes// +├── background.webp +├── frames/ +│ ├── manifest.json +│ └── *.png +├── icons/ +│ ├── manifest.json +│ └── *.png +└── textures/ + └── *.webp +``` + +专项回归至少覆盖: + +- 主题注册、可见性和迁移策略。 +- 变量块和专属组件层存在。 +- 新主题加入必要共享 selectors。 +- 静态/动态 welcome 同步。 +- 本地资产格式、尺寸、hash 或 manifest。 +- 禁止远程 URL。 +- 动态组件的结构契约,例如可伸缩输入框不依赖固定伪元素。 +- 响应式、reduced-motion、文字对比度。 +- cache bust 与在线加载版本一致。 +- 旧主题专项回归继续通过。 + +回归验证结构和不变量,不替代像素与构图验收。 + +## 6. 脏工作树与服务约束 + +- 实施前执行 `git status --short` 和主题相关精确 diff。 +- 记录相关文件的起始状态;只修改目标区块。 +- 不使用 `git reset --hard`、`git checkout --` 或整文件还原保护自己生成的改动。 +- 多会话可能同时修改 `app.js`、`style.css`、`index.html` 和 `regression.js`。发现反复回写时停止覆盖,先协调写入边界。 +- 修改静态文件通常不需要重启服务。需要重启 cc-web 时,严格执行仓库 `AGENTS.md` 的运行会话检查。 +- 浏览器访问失败时先用 `curl http://127.0.0.1:` 检查本地服务,再按 `hostname -I` 使用 `11.144.144.*` 地址排除网络命名空间问题。 diff --git a/.codex/skills/create-cc-web-theme/references/lessons-learned.md b/.codex/skills/create-cc-web-theme/references/lessons-learned.md new file mode 100644 index 0000000..1d44e01 --- /dev/null +++ b/.codex/skills/create-cc-web-theme/references/lessons-learned.md @@ -0,0 +1,185 @@ +# 主题创作经验教训 + +## 目录 + +1. 完成标准 +2. 构图与装饰 +3. 边框与动态尺寸 +4. 图标与重复来源 +5. 透明度与选择器 +6. 居中、菜单与动态 DOM +7. 范围控制与缓存 + +## 1. 完成标准 + +### 教训:自动化通过不代表像设计图 + +症状:资产存在、选择器命中、回归全绿,但用户第一眼认为“完全不是一个东西”。 + +根因:回归只能证明结构契约,不能证明构图比例、边框轻重、视觉层级和图标质感。 + +做法: + +- 把真实浏览器视觉对照列为独立完成阶段。 +- 按参考图原始视口先验收,再做响应式。 +- 为关键区域记录截图、几何值和 computed style。 +- 用户未确认或对照差异明显时,回滚“完成”状态。 + +## 2. 构图与装饰 + +### 教训:参考图不是配色板 + +症状:颜色接近,但人物被遮罩压黑、侧栏比例不对、卡片堆叠、整体质感跑偏。 + +根因:只抽取黑、金、棕等颜色,没有量化参考图的空间、留白和主视觉安全区。 + +做法:先量化侧栏/顶栏/输入区比例、主视觉 bbox、阅读安全区和面板覆盖范围。 + +### 教训:主题感不是“给所有组件加边框” + +症状:搜索框、消息、列表、弹层、工具块全都厚金边和切角,界面像重型游戏皮肤。 + +根因:把局部装饰语言泛化到所有组件。 + +做法:建立装饰预算。只让主按钮、输入框和少数工具框承担强边框;普通消息、列表和小标签使用轻线或无边框。 + +### 教训:先删重,再加细节 + +症状:越修越多伪元素、渐变、阴影和粒子,参考主体反而更弱。 + +做法:按“背景 → 大布局 → 面板 → 边框 → 图标 → 微交互”排序。发现层级错误时先删除多余装饰,不继续叠覆盖规则。 + +## 3. 边框与动态尺寸 + +### 教训:固定比例伪元素不适合动态输入框 + +症状:单行看似正确,多行内容后边框、底线或徽记偏移;窄屏出现非等比压缩。 + +根因:把固定 `width/height` 比例的整框放在 `::before`/`::after`,它不跟随真实内容盒的边界语义。 + +做法: + +- 动态宽高使用 `border-image`/九宫格。 +- 把不能拉伸的徽记和可拉伸边线分开。 +- 测试最短、常规和最大高度。 +- focus/drag/note 状态不要用 `border: 0` 破坏 frame。 + +### 教训:莫名边框通常来自叠层,不是主框 + +症状:按钮旁多出框、输入区出现虚线、聚焦后冒出第二层边。 + +根因:旧 focus ring、按钮 `::after`、背景素材烘焙线、主框图片内外双线同时存在。 + +做法:在 DevTools 逐个关闭伪元素、border、outline、box-shadow 和背景图,确定真实来源后只删那一层。 + +## 4. 图标与重复来源 + +### 教训:统一画布不等于统一视觉尺寸 + +症状:CSS 都是 24px,但图标仍显得过小、过大或偏心。 + +根因:透明画布内的 alpha 主体 bbox 不同;不同形状的光学重心也不同。 + +做法:记录源规格、输出画布、alpha bbox 和实际 CSS 尺寸;非对称图标按 alpha 重心校正。 + +### 教训:最大档切图缩小不一定更清晰 + +症状:64px 原色 PNG 缩到 18–24px 后灰边、糊、材质脏。 + +根因:有损素材板中的半透明暗边和高光被浏览器重采样到很小区域。 + +做法:主交互控件重切对应规格并制作干净 mask;多色状态和头像保留原色但独立裁切。 + +### 教训:新图标可能叠在旧图标上 + +症状:头像两个图、新会话加号消失/重复、发送按钮出现“一坨”。 + +根因:真实 DOM 已有文字、SVG 或 ``,主题又添加了背景图或伪元素。 + +做法:先检查 DOM。每个语义只保留一个视觉来源;只在目标主题下隐藏原生子节点。 + +## 5. 透明度与选择器 + +### 教训:RGBA 很低仍可能看起来不透明 + +症状:外层气泡改为 2%–10% alpha,页面仍像实心黑卡片。 + +根因可能包括: + +- 内层 tool-call/content/title 仍是 90% 黑底。 +- blur 太高,把背景细节抹成均匀色块。 +- 旧规则用更高 specificity 锁住 background。 +- 伪元素仍覆盖整层。 + +做法:从最外层到最内层检查 computed background、background-image、opacity、backdrop-filter 和伪元素。用背景纹理是否可辨判断“透”,不用数值自我证明。 + +### 教训:`backdrop-filter` 变了不代表背景色也变了 + +症状:DevTools 显示 blur 已更新,但气泡底色完全不变。 + +根因:共享 `:is()` 规则的最高参数 specificity 超过后置主题规则。 + +做法:查看每个 computed 属性的获胜规则;使用同级 selector 或只对冲突属性精确增加 `!important`。不要把 `!important` 扩散到整个主题。 + +### 教训:模糊强度不是越高越有磨砂感 + +症状:提高 blur 后背景更像不透明色块。 + +根因:暗场细节被平均,透景消失。 + +做法:先降低染色层,再用较小 blur 配合适度 saturate/brightness;最终数值按当前背景实测,不把某个主题的 `blur(3px)` 当通用常量。 + +## 6. 居中、菜单与动态 DOM + +### 教训:CSS “居中”需要测量证据 + +症状:代码有 flex/absolute 50%,视觉仍偏。 + +根因:容器本身不在画布中心、baseline 不一致、图片 alpha 主体偏心或滚动条改变内容区中心。 + +做法:分别测容器中心、画布中心、图标 alpha 中心和文字 line box;记录像素差后修正。 + +### 教训:菜单没显示可能是被父级裁切 + +症状:点击后状态正确,菜单 DOM 也存在,但看不到。 + +根因:列表项 `overflow: hidden`、错误 stacking context 或按钮被 flex 挤出。 + +做法:检查展开态 overflow、定位基准、z-index 和操作区尺寸。只在菜单打开时解除必要裁切。 + +### 教训:静态与动态 welcome 会漂移 + +症状:首次打开显示旧文案,刷新/切会话后才正确;结构修了一处另一处仍旧。 + +根因:`index.html` 与 `buildWelcomeMarkup()` 是两条渲染路径。 + +做法:结构同步,动态文案使用同一 formatter/hydration 节点;回归同时读取静态与动态源码。 + +## 7. 范围控制与缓存 + +### 教训:用户圈的是哪层,就只改哪层 + +症状:用户要求气泡透明,却修改了所有卡片、工具层或整页背景,导致更多视觉偏差。 + +做法:先用 DOM/DevTools 确认用户所指层级,明确 selector 列表;超出范围的发现只记录,不顺手实施。 + +### 教训:选择器写错会让正确元素消失 + +症状:加号消失或旧规则继续生效。 + +根因:假定 class 名,没有检查真实 DOM;新 selector 命中不存在节点,旧隐藏规则仍命中真实节点。 + +做法:实现前用 `rg` 和浏览器检查实际 class,回归断言真实节点保持所需显示状态。 + +### 教训:缓存会制造“完全没变化”的假象 + +做法: + +- 修改 CSS/JS 后推进 cache-busting query。 +- 用浏览器读取实际 ``/` - + @@ -47,7 +51,7 @@