Files
classhelper-island-refactor…/out/sections/15-assets.md
T
ClassIsland Prompt Kit 22c1784bab feat: ClassIsland / ClassHelper 灵动岛提示词套件
- 重构版主提示词(14 parts,面向 ClassHelper 灵动岛重构)
- ClassIsland 全量规格提示词(20 parts,含分卷与逐章版本)
- 投喂指南、分卷、逐节文件
- 调研记录、一致性基线、生成与质检脚本
2026-11-12 21:59:58 +08:00

315 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 15. 资源清单(图标 / 字体 / 音效 / 天气图标 / 教程 / 本地化)
本节要求实现者**按清单准备并放置资源**,不得缺项、不得自行替换为网络图片。所有路径均以 ClassIsland 仓库为参照;实现时统一放到 `packages/desktop-client/src/renderer/assets/`(渲染进程资源)与 `packages/desktop-client/resources/`(打包资源)两处,并通过构建脚本生成多尺寸产物(见 15.9)。
### 15.1 应用图标
#### 15.1.1 主图标(多尺寸 PNG)
| 文件 | 尺寸 | 用途 | 证据 |
|---|---|---|---|
| `Assets/AppLogo.png` | 192×192 | 应用内窗口图标、关于页、欢迎页 Logo | `ClassIsland/Assets/AppLogo.png`;`App.axaml:29-31`;`WelcomePage.axaml:29-33` |
| `Assets/AppLogo@48w.png` | 48×48 | 小尺寸(任务栏/列表) | 实测文件头 |
| `Assets/AppLogo@384w.png` | 384×384 | 中尺寸(设置页/关于页展示) | 实测文件头 |
| `Assets/AppLogo@768w.png` | 768×768 | 大尺寸(高分屏) | 实测文件头 |
| `Assets/AppLogo_Fade.png` | 192×193 | 淡入用的半透明 Logo(启动/遮罩) | 实测文件头 |
| `Assets/AppLogo_Monochrome.png` | 2715×2003 | 单色 Logo(水印/背景纹样) | 实测文件头 |
| `Assets/AppLogo_AppLogo.svg` | 矢量 | 可缩放图标源 | 文件名 |
| `Assets/AppLogo.ico` | 多尺寸 ICO:16/24/32/48/64/256×2 | Windows 可执行文件图标 | 解析 ICO 头得 7 个条目 |
| `Assets/FreedesktopIcons/AppLogo@128w.png` | 128×128 | Linux Freedesktop 图标 | 实测文件头 |
| `AppLogo@32w.png`(`ClassIsland.Desktop/Assets/`) | 32×32 | Windows 任务栏/托盘小图标 | 实测文件头 |
#### 15.1.2 macOS 图标集(`ClassIsland.Desktop/Assets/AppLogo.xcassets/AppIcon.appiconset/`)
必须提供:16×16(1x/2x)、32×32(1x/2x)、128×128(1x/2x)、256×256(1x/2x)、512×512(1x/2x)、以及无后缀的 192/384/768 三档。实测目录内共 16 个 PNG,命名遵循 `AppLogo_<尺寸>_<倍率>.png` 与 `AppLogo@<宽>w.png` 两种规则,实现时按 `electron-builder` 的 `icon.icns` 要求重新生成即可,但**必须保留这两个命名族**以免资源引用失效。
#### 15.1.3 Windows 打包瓦片(`ClassIsland.Packaging/Images/`)
| 资源 | 尺寸(100%/200%/400%) | 用途 |
|---|---|---|
| `Square44x44Logo` | 44 / 88 / 176 | 开始菜单小图标 |
| `Square44x44Logo.targetsize-16/24/48/256` | 16/24/48/256 | 任务栏/Alt-Tab 变体 |
| `Square150x150Logo` | 150 / 300 / 600 | 开始菜单中等图标 |
| `Wide310x150Logo` | 310×150 / 620×300 / 1240×600 | 宽幅磁贴 |
| `LargeTile` | 310 / 620 / 1240 | 大磁贴 |
| `SmallTile` | 71 / 142 / 284 | 小磁贴 |
| `StoreLogo` | 50 / 100 / 200 | 商店图标 |
| `SplashScreen` | 620×300 / 1240×600 / 2480×1200 | 系统级启动图(与自绘闪屏无关) |
| `LockScreenLogo` | 48×48 | 锁屏 |
(以上均为实测文件头尺寸;`ClassIsland/Images/` 下另有一份 `.scale-200` 版本,实现时只保留打包用的那份即可。)
#### 15.1.4 其他图标
| 资源 | 尺寸 | 用途 |
|---|---|---|
| `Assets/Marketplace/Logo.png` | 512×512 | 插件/主题市场 Logo |
| `Assets/Marketplace/Logo@256w/128w/64w.png` | 256/128/64 | 市场图标多尺寸 |
| `Assets/Marketplace/Logo.svg` | 矢量 | 市场矢量源 |
| `ClassIsland.ExamplePlugin/icon.png` | 510×510 | 示例插件图标(插件必须自带 510×510 图标) |
| `ClassIsland.Launcher/Assets/AppLogo.ico` | 18 条目 ICO(16–256) | 启动器图标 |
验收要求:所有图标必须**本地打包**、离线可用;PNG 必须由同一矢量源派生,不得出现「不同尺寸风格不一致」;ICO 必须内嵌 16/24/32/48/64/256 六档。
### 15.2 字体
#### 15.2.1 正文/界面字体:HarmonyOS Sans SC
| 文件 | 字重 | 用途 | 证据 |
|---|---|---|---|
| `Assets/Fonts/HarmonyOS_Sans_SC_Light.ttf` | 300 | 轻量标题/水印 | 文件名 |
| `Assets/Fonts/HarmonyOS_Sans_SC_Regular.ttf` | 400 | 正文 | 文件名 |
| `Assets/Fonts/HarmonyOS_Sans_SC_Medium.ttf` | 500 | 默认字重(岛内主文字) | `Settings.cs:101` |
| `Assets/Fonts/HarmonyOS_Sans_SC_Bold.ttf` | 700 | 标题/强调 | 文件名 |
- 字体族注册名:`HarmonyOS Sans SC`;全局资源键 `AppFont`,字体栈见 part 03 §3.2.1(`Assets/Fonts/Fonts.axaml:3`;`Assets/Fonts/Fonts.xaml:3`)。
- **许可**:`Assets/Fonts/LICENSE.txt` 为「HarmonyOS Sans Fonts License Agreement」,版权归华为;分发时必须**原样保留**该许可文件,且不得单独售卖字体。应用本体为 GPL-3.0(`LICENSE.txt`),字体许可与代码许可分离。
- 实现要求:把 4 个 ttf 放进 Electron 打包资源,`@font-face` 声明 4 个 `font-weight`,`font-display: swap`;**禁止**声明 `font-display: block`(会白屏到字体加载完)。
#### 15.2.2 图标字体(三套,必须全部内置)
| 字体 | 文件 | 大小 | 附带映射 | 用途 | 证据 |
|---|---|---|---|---|---|
| Fluent System Icons | `ClassIsland.Core/Assets/Fonts/FluentSystemIcons-Resizable.ttf` | 1,472,748 B | `FluentSystemIcons-Resizable.json`(262,830 B) | 全局 UI 图标(Segoe Fluent 风格) | `AppBase.cs:142`;`ThemeBase.axaml:46` |
| Lucide | `ClassIsland.Core/Assets/Fonts/lucide.ttf` | 715,192 B | `lucide.json`(45,030 B) | 天气图标(默认)、部分 UI 图标 | `AppBase.cs:147`;`ThemeBase.axaml:47` |
| SF Symbols | `ClassIsland.Core/Assets/Fonts/SF-Symbols.ttf` | 174,616 B | — | 天气图标(Apple 风格) | `AppBase.cs:152` |
- 字体族名分别为 `FluentSystemIcons-Resizable`、`lucide`、`SF-Symbols`;Avalonia 资源 URI 形如 `avares://ClassIsland.Core/Assets/Fonts/#lucide`,Web 实现改为 `@font-face { font-family:'lucide'; src:url('lucide.ttf') }` 并保留同名 `font-family`。
- JSON 映射文件必须作为图标选择器数据源(Codepoint/名称表),不得只带 ttf 不带 json——图标选择器需要按名称搜索。
- 许可:应用整体 GPL-3.0;Fluent System Icons 与 Lucide 通常为 MIT/ISC【推断:仓库内未放独立许可文件,按上游项目许可执行】;SF Symbols 字体来自 Apple 符号集,**仅允许在 Apple 平台或已获授权场景使用**,跨平台分发时须评估并在「关于/许可」页声明。
#### 15.2.3 字体相关的硬性要求
1. 字体必须在应用启动**首帧前**注册完成(`document.fonts.ready` 前不得渲染最终布局,可用 `font-display: swap` + 骨架屏规避跳动)。
2. 不得使用系统缺失字体作为唯一来源;`HarmonyOS Sans SC` 必须随包分发。
3. 用户自定义字体(`MainWindowFont`)只允许从**系统已安装字体**中选择(源码 `AppearanceSettingsPage.axaml:409-446` 枚举系统字体),实现时用 `queryLocalFonts()`(需权限)或主进程枚举字体列表,二者都不可用时至少提供内置 4 字重 + 3 图标字体。
4. 字体文件不得被 CSP 阻止:`font-src 'self'` 必须放行本地资源。
### 15.3 音效
| 资源 | 大小 | 用途 | 默认设置 | 证据 |
|---|---|---|---|---|
| `Assets/Media/Notification/1.wav` | 130,012 B | 提醒音效(唯一内置音效) | `IsNotificationSoundEnabled=true`;`NotificationSoundPath=""`(表示使用内置音效);`NotificationSoundVolume=1.0` | 实测文件;`Settings.cs:144-145,1584-1593` |
| 自定义音效 | 用户文件 | 用户可指定本地音频路径 | 支持 wav/mp3 等系统可解码格式【推断】 | `Settings.cs:1496-1505` |
| 语音合成 | 系统/Edge TTS | 提醒朗读 | `IsSpeechEnabled=true`;`SpeechVolume=1.0`;`SpeechSource=0`;Edge TTS 默认音色 `zh-CN-XiaoxiaoNeural` | `Settings.cs:135-139,1406-1428,1452-1461` |
实现要求:
- 音频必须用 `HTMLAudioElement` 或 Web Audio 播放,**不得**在主进程用系统播放器;播放前需用户手势解锁(Electron 可用 `webPreferences.autoplayPolicy: 'no-user-gesture-required'`,但必须在配置中显式声明)。
- 音量 = `NotificationSoundVolume × 系统音量`,范围 0–1;语音音量独立(`SpeechVolume`)。
- 同一条提醒**只播一次**音效(源码用 `MaskSession.HasSoundsPlayed` 去重,`MainWindowLine.cs:746-751`);提醒队列切换时不得重复触发。
- 语音提供方必须可插拔:系统语音(Windows SAPI)、Edge TTS、GPT-SoVITS 三选一(`App.Services.xaml.cs:281-285` 注册三个 provider),默认走系统语音或 Edge TTS,且必须支持「无网络时降级到系统语音」。
- 内置音效 1.wav 必须打包进 `resources/audio/`,不得 CDN 引用。
### 15.4 天气图标(4 套模板)
#### 15.4.1 模板注册表
| 模板 id | 显示名 | 默认 | 实现方式 | 尺寸参数 | 证据 |
|---|---|---|---|---|---|
| `classisland.weatherIcons.lucide` | Lucide(默认) | ✅ `WeatherIconId="classisland.weatherIcons.lucide"` | `Viewbox` + `LucideIcon` | 16×16,FontSize 16,Margin 1 | `App.Services.xaml.cs:287`;`Settings.cs:2106`;`LucideWeatherIconTemplate.axaml` |
| `classisland.weatherIcons.fluentDesign` | Fluent Design | — | `Viewbox` + `FluentIcon` | 20×20,FontSize 24,Margin `0 1.2 0 -1.2` | `App.Services.xaml.cs:288`;`FluentDesignWeatherIconTemplate.axaml` |
| `classisland.weatherIcons.sfSymbols` | SF Symbols | — | `Viewbox` + `SFSymbolsIcon` | 16×16 | `App.Services.xaml.cs:289`;`SFSymbolsWeatherIconTemplate.axaml` |
| `classisland.weatherIcons.simpleText` | 纯文本 | — | 文本 + 分隔符 `~` | 文本随字号 | `App.Services.xaml.cs:290`;`SimpleTextWeatherIconTemplate.axaml` |
实现要求:模板必须可插拔(插件可注册新模板),模板注册信息至少包含 `{id, name, renderer}`;切换模板立即生效且不需要重启(源码 `WeatherService.LoadWeatherIconTemplate()` 在设置变化时重新取模板,`Services/WeatherService.cs:84-90`)。
#### 15.4.2 天气代码 → 名称 → 图标(必须完整映射,共 40 个代码)
数据源:小米天气状态表 `Assets/XiaomiWeather/xiaomi_weather_status.json`;图标映射:`ClassIsland/Converters/WeatherConverters.cs`。下表前端三列(Fluent/Lucide/SF)为源码私有区码位,后端实现时请**原样保留码位**,Web 端用 `data-icon` 名称 + 本地字体渲染。
| code | 天气名 | Fluent 码位 | Lucide 码位 | SF 码位 |
|---|---|---|---|---|
| 0 | 晴 | `\uf465` | `\ue2b1` | `\uFE42` |
| 1 | 多云 | `\uf44f` | `\ue216` | `\uFDC9` |
| 2 | 阴 | `\uf43d` | `\ue217` | `\uFDF1` |
| 3 | 阵雨 | `\uf455` | `\ue2fb` | `\uFDE9` |
| 4 | 雷阵雨 | `\uf46b` | `\ue090` | `\uFDCD` |
| 5 | 雷阵雨并伴有冰雹 | `\uf46b` | `\ue08f` | `\uFDDD` |
| 6 | 雨夹雪 | `\uf459` | `\ue094` | `\uFDD4` |
| 7 | 小雨 | `\uf43f` | `\ue08e` | `\uFDED` |
| 8 | 中雨 | `\uf453` | `\ue092` | `\uFDE9` |
| 9 | 大雨 | `\uf453` | `\ue092` | `\uFDE5` |
| 10 | 暴雨 | `\uf453` | `\ue093` | `\uFDE4` |
| 11 | 大暴雨 | `\uf453` | `\ue093` | `\uFDE4` |
| 12 | 特大暴雨 | `\uf453` | `\ue093` | `\uFDE4` |
| 13 | 阵雪 | `\uf45d` | `\ue376` | `\uFDD9` |
| 14 | 小雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 15 | 中雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 16 | 大雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 17 | 暴雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 18 | 雾 | `\uf443` | `\ue214` | `\uFDE1` |
| 19 | 冻雨 | `\uf461` | `\ue08f` | `\uFDD5` |
| 20 | 沙尘暴 | `\uf441` | `\ue218` | `\uFDB1` |
| 21 | 小雨-中雨 | `\uf453` | `\ue092` | `\uFDED` |
| 22 | 中雨-大雨 | `\uf453` | `\ue092` | `\uFDE9` |
| 23 | 大雨-暴雨 | `\uf453` | `\ue093` | `\uFDE5` |
| 24 | 暴雨-大暴雨 | `\uf453` | `\ue093` | `\uFDE5` |
| 25 | 大暴雨-特大暴雨 | `\uf453` | `\ue093` | `\uFDE5` |
| 26 | 小雪-中雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 27 | 中雪-大雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 28 | 大雪-暴雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 29 | 浮尘 | `\uf449` | `\ue0f4` | `\uFE2E` |
| 30 | 扬沙 | `\uf441` | `\ue0f4` | `\uFE2E` |
| 31 | 强沙尘暴 | `\uf441` | `\ue218` | `\uFE2E` |
| 32 | 飑 | `\uf463` | `\ue093` | `\uFDAD` |
| 33 | 龙卷风 | `\uf463` | `\ue218` | `\uFDA3` |
| 34 | 弱高吹雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 35 | 轻雾 | `\uf443` | `\ue214` | `\uFDE1` |
| 53 | 霾 | `\uf449` | `\ue0f4` | `\uFDE1` |
| 301 | 雨 | `\uf453` | `\ue092` | `\uFDE9` |
| 302 | 雪 | `\uf45b` | `\ue094` | `\uFDD9` |
| 99 及未知 | 未知 | `\uee31` | `\ue091` | `\uFD8C` |
实现硬要求:
- 未知代码必须回落到「未知」图标,**不得**抛异常或显示空白。
- 纯文本模板必须实现「今天~明天」的 `~` 分隔符逻辑(模板内 `Separator` 仅在 `To` 场景可见,`SimpleTextWeatherIconTemplate.axaml`),且文本颜色跟随 `--ci-text-*`。
- 天气图标颜色:晴天/温度等常规图标用前景色;雨天图标可选用 `--ci-weather-rain`(亮 `#0000FF` / 暗 `#00BFFF`),见 part 03。
### 15.5 贴纸资源(HoYoStickers)
`Assets/HoYoStickers/` 内共 **22** 个 PNG,按「角色_动作」命名,用于教程/提醒的图标表达式 `sticker(名字)`(`App.axaml.cs:253` 注册 `IconExpressionHelper` 的 `sticker` 处理器)。实现时必须支持 `sticker(帕姆_嗨)` 这种写法并渲染对应 PNG。
| 角色 | 尺寸 | 文件(动作) |
|---|---|---|
| 光辉矢愿 | 162×162(6 个) | `不可以看`、`回眸`、`小喇叭`、`想我了吗`、`瞄准`、`遨游` |
| 帕姆 | 510×510(5 个)/450×450(1 个) | `不可以`、`哭哭`、`嗨`(450)、`注意`、`点赞`、`震惊` |
| 昔涟 | 510×510(4 个) | `回眸`、`守护`、`收到`、`爱` |
| 白厄 | 510×510(6 个) | `再见`、`我吗`、`战斗`、`掉线`、`没事` |
实现要求:贴纸必须按**原始比例**缩放(`object-fit: contain`),不得拉伸;建议在 UI 中统一缩放到 96×96 或 128×128,并保留 `image-rendering: -webkit-optimize-contrast` 以求清晰。图标表达式解析器必须支持 `fluent(码位)`、`lucide(码位)`、`sfsymbols(码位)`、`bitmap(路径)`、`sticker(名字)` 五种前缀(`App.axaml.cs:250-260`),未知前缀回落为文本。
### 15.6 教程资源
#### 15.6.1 教程定义文件(JSON)
内置教程组:`Assets/Tutorials/classisland.getStarted.json`(另有 `classisland.sp.json`、`classisland.test.json` 仅作开发样例,**不要**在正式版启用)。数据结构(逐字段实现):
| 层级 | 字段 | 类型 | 说明 |
|---|---|---|---|
| 顶层 | `Id` | string | 教程组 id,如 `classisland.getStarted` |
| 顶层 | `Title` / `Description` | string | 组标题/描述(中文) |
| 顶层 | `Tutorials` | array | 教程条目列表 |
| 教程 | `Id` / `Title` / `Description` | string | 教程 id/标题/描述 |
| 教程 | `ActualBanner` / `Banner` | string | Banner 资源 URI(`avares://`) |
| 教程 | `Ordinary` | int | 是否为普通教程(0/1) |
| 教程 | `Paragraphs` | array | 段落列表 |
| 段落 | `Id` / `Title` / `Description` | string | 段落标识/标题/描述 |
| 段落 | `TopLevelClassName` | string | 目标窗口类名(如 `ClassIsland.MainWindow`) |
| 段落 | `IsBarrierEnabled` | bool | 是否启用教程遮罩屏障 |
| 段落 | `InitializeActions` | array | 进入段落时执行的行动 |
| 段落 | `Content` | array | 每屏内容 |
| 内容 | `Title` / `Content` | string | 标题/正文(中文) |
| 内容 | `IconExpression` | string | 图标表达式(如 `sticker(帕姆_嗨)`) |
| 内容 | `HeroImage` | string | 大图 URI(可空) |
| 内容 | `TargetSelector` / `PointToTarget` / `ModalTarget` | string/bool | 指向的目标与是否模态 |
| 内容 | `RightButtonText` / `LeftButtonText` | string | 按钮文案(可空) |
| 内容 | `RightButtonActions` / `LeftButtonActions` / `InitializeActions` | array | 行动列表,元素为 `{Kind:int, StringParameter:string}` |
| 内容 | `WaitForNextCommand` / `UseLightDismiss` | bool | 交互策略 |
| 内容 | `Tag` / `Script` / `Xmlns` | string/object | 扩展位 |
(来源:`Assets/Tutorials/classisland.getStarted.json:1-200+`。行动 `Kind` 的具体枚举含义在源码 `TutorialActionKind` 中定义,实现时必须对照该枚举逐值映射,不得自行编号;本节不臆造枚举值。)
#### 15.6.2 教程图片
| 组/条目 | 文件 | 大小 |
|---|---|---|
| welcome | `banner.webp` | 42,664 B |
| welcome | `mainMenu.webp` / `openAppSettings.webp` / `openEditMode.webp` / `openProfileEditor.webp` / `openTutorial.webp` | 约 25–27 KB/张 |
| componentsEditing | `banner.webp` / `ruleset.webp` | 28,292 / 48,738 B |
| profileEditing | `banner.webp` / `时间表.webp` / `科目.webp` / `课表.webp` / `课表与时间表关系.webp` | 25,900–109,912 B |
另有默认图:`Assets/DefaultTutorialBanner.webp`(10,416 B)、`Assets/DefaultTutorialGroupBanner.webp`(46,540 B),用作无 Banner 时的兜底。
要求:图片统一用 WebP(保留 `.webp` 扩展名),懒加载;教程播放时按窗口宽度自适应,不得变形。
### 15.7 本地化
#### 15.7.1 现状(必须如实实现,不得虚构更多语言)
ClassIsland v2 的本地化是**局部**的,只覆盖两个命名空间(`Assets/Localization/`):
| 命名空间 | 资源文件 | 语言 |
|---|---|---|
| `SettingsPage`(设置页) | `Localization.SettingsPage.resx`(默认/中文)、`.zh-Hans.resx`、`.zh-Hant.resx`、`.en.resx` | 简体中文、繁体中文、英文 |
| `SettingsPage/General`(常规设置子页) | 同上 4 个 | 同上 |
| `TrayMenu`(托盘菜单) | 同上 4 个 | 同上 |
- 默认语言为中文(`resx` 无文化后缀文件即默认),并强制 `Thread.CurrentThread.CurrentUICulture = zh-CN`(`ClassIsland/App.axaml.cs:512-513`)。
- 其余界面文案**硬编码中文**,没有资源化。因此「支持多语言」不是现状能力。
#### 15.7.2 实现要求(在 Web 栈中的等价方案)
1. 必须建立 `i18n` 层(推荐 `vue-i18n`),语言键命名与 resx 的 `Key` 保持一致,便于数据迁移。
2. 首期必须提供 **zh-Hans(默认)、zh-Hant、en** 三份文案;其余界面文案随实现逐步资源化,**不得**伪造「已支持 N 种语言」。
3. 语言切换必须持久化到配置,并立即刷新界面(无需重启);日期/时间格式必须跟随语言(`Intl.DateTimeFormat`)。
4. 本地化文件不得包含 HTML 标签;带占位符的文案必须使用命名参数(`{name}`),禁止字符串拼接。
5. 字体必须覆盖三语:英文用 HarmonyOS Sans SC 的拉丁字形即可;繁体中文若依赖系统字体兜底,必须在 fallback 栈中显式列出(`PingFang TC`、`Microsoft JhengHei`)。
### 15.8 其他资源与文档
| 资源 | 用途 | 要求 | 证据 |
|---|---|---|---|
| `Assets/Documents/ChangeLog.md` | 更新日志(关于页展示) | 必须随版本更新,按版本倒序 | 文件名 |
| `Assets/Documents/Privacy_.md` | 隐私政策(关于页展示) | 必须原样保留;含 Sentry/上报说明 | 文件名 |
| `LICENSE.txt`(根、各项目、Assets) | GPL-3.0 许可证 | 必须随安装包分发 | `LICENSE.txt` |
| `Assets/TrustedPublicKeys/ClassIsland.MetadataPublisher.asc` | 更新/市场元数据签名公钥 | 必须内置,用于校验更新包 | 文件名 |
| `Assets/ShortcutTemplates/ClassSwap.url`、`cn.classisland.app.desktop` | 换课/桌面快捷方式模板 | Windows `.url` 与 Linux `.desktop` 两套 | 文件名 |
| `Assets/Highlighting/Lua.xshd` | 自动化脚本 Lua 语法高亮定义 | 编辑器必须使用该配色 | 文件名 |
| `Assets/default-subjects.json` | 默认科目表(23 个科目,含固定 GUID:语文/数学/英语/历史/政治/物理/化学/生物/地理/信息技术/体育/自习/通用技术/音乐/美术/选修课/社团/心理/早读/班会/周测 等) | 必须原样内置,GUID 不得重新生成(迁移依赖) | `Assets/default-subjects.json` |
| `Assets/AsciiLogo.txt` | ASCII 艺术 Logo(控制台/崩溃页) | 6 行,宽 63 字符 | 文件内容 |
| `Assets/Tellings.txt` | 关于页/加载页随机「一句话」(含彩蛋) | 至少 20 条,需保留「关于页连续点击图标 10 次开调试」等提示 | 文件内容 |
| `Assets/dependencies.g.json` | NuGet 依赖许可清单(供「许可」页展示) | Web 栈需生成 `licenses.json` 等价物(npm 依赖 + 字体许可) | `Models/NugetLicenseInfo.cs`、`Views/WelcomePages/LicensePage.axaml` |
| `Assets/XiaomiWeather/xiaomi_weather_status.json` | 天气代码→中文名映射(40 条) | 与 15.4.2 表一致 | 文件内容 |
| `Assets/BannerMain_App2.png` | 2031×600 | 关于页/更新页主视觉 | 实测文件头 |
| `Assets/Demo_MainMenu.png`、`Demo_OpenProfileSettingsWindow.png` | 1608×878 | 教程/引导演示图 | 实测文件头 |
| `Assets/ClassIsland.ai` | 矢量源文件 | 设计源文件,可不打包 | 文件名 |
| `Assets/XamlThemePreviews/classisland.fluent.png`、`classisland.classic.png` | 1920×350 | 主题市场预览图(见 part 09) | 实测文件头 |
### 15.9 ClassHelper 侧资源落点
| 资源类别 | 落点 | 生成/校验方式 |
|---|---|---|
| 应用图标 | `build/classhelper.png`(源)+ 设计导出的 `.ico` | 用 `pnpm icons` 派生其余尺寸(与 ClassHelper 现有约定一致:图标源是 `build/classhelper.png` 与设计导出的 `.ico`,`pnpm icons` 派生其余资源) |
| Web 品牌图 | `packages/web-admin/public/logo.png` 或站点 `/logo.png` | Web 用 `/logo.png`,客户端用 `BRAND_LOGO_URL` 常量(避免 `file://` 绝对路径问题) |
| 字体 | `packages/desktop-client/resources/fonts/` | 4 个 HarmonyOS TTF + 3 个图标 TTF + 2 个 JSON 映射;构建时校验文件存在与哈希 |
| 音效 | `packages/desktop-client/resources/audio/1.wav` | 校验大小 130,012 B(或替换为等价资源但保持单文件、可循环) |
| 贴纸 | `packages/desktop-client/resources/stickers/` | 22 个 PNG,文件名保持中文原名(打包后可用 URL 编码访问) |
| 教程 | `packages/desktop-client/resources/tutorials/` | JSON + WebP;启动时校验 id 唯一 |
| 主题预览 | `packages/desktop-client/resources/theme-previews/` | 1920×350 PNG 两张 |
| 许可清单 | `packages/desktop-client/resources/licenses.json` | 构建时从 `package.json`/`node_modules` 生成;必须包含字体与图标字体的许可条目 |
### 15.10 资源命名、加载与缓存规范
1. **命名**:图片用 `kebab-case` 或保持中文原名(贴纸、教程图必须保留原名,因为教程 JSON 以名字引用);字体文件名保持上游原名(`HarmonyOS_Sans_SC_Medium.ttf`),不得改成 `medium.ttf` 之类丢失来源信息的名字;音效用 `1.wav` 这类稳定短名,便于设置里持久化路径。
2. **目录约定**:`renderer/assets/{icons,fonts,audio,stickers,tutorials,theme-previews}/`,每类一个目录;禁止在组件目录里散落资源文件。
3. **加载方式**:
- 图标字体、正文 TTF 在应用启动时通过 `@font-face` 预加载(`crossorigin` 同源),并用 `document.fonts.load()` 显式触发;
- 贴纸/教程图/主题预览图走懒加载(`loading="lazy"` + IntersectionObserver),未加载时显示 `Shimmer` 骨架(part 14 D9);
- 音效在首次提醒时按需加载并缓存 `AudioBuffer`,不得每次播放都重新 `fetch`。
4. **缓存**:所有资源 URL 必须带内容哈希(构建期生成 `asset-manifest.json`),Electron 生产环境用 `file://` + 哈希避免陈旧缓存;开发环境禁用强缓存。
5. **失败降级**:图片加载失败必须显示「图裂了」占位(ClassIsland 的行为:`SystemFillColorCriticalBackgroundBrush` 底 + 提示「喔唷,图裂啦」,`StylesBase.axaml:214-223`),不得留白或抛错;字体加载失败必须回落系统字体并保持布局不跳变(用 `font-display: swap` + 固定行高)。
6. **安全**:禁止加载 `http(s)` 远程图片作为 UI 资源;所有资源必须走打包路径,CSP 中 `img-src 'self' data:`、`font-src 'self'`、`media-src 'self'`。
7. **引用完整性**:构建时扫描 CSS/TS/JSON 中的资源引用,所有引用必须命中 `asset-manifest.json`;反向扫描资源目录,未被引用的资源要么删除要么登记为「运行时动态加载」白名单。
### 15.11 资源版本与许可核对
- 「关于」页必须提供「许可」入口,展示:应用许可(GPL-3.0)、字体许可(HarmonyOS Sans License)、图标字体许可(Fluent/Lucide/SF)、贴纸素材来源、第三方依赖(npm 依赖清单)。ClassIsland 用生成文件 `dependencies.g.json` + `LicensePage.axaml` 展示 NuGet 依赖,Web 实现必须生成等价的 `licenses.json`。
- 每次发版必须核对:新增/替换的资源是否引入新的许可义务;贴纸、Banner、Demo 图是否为项目自有或有授权(HoYoStickers 为《崩坏:星穹铁道》同人素材,**仅可作为内置彩蛋、不得用于商业宣传**)。
- 版本号变更时必须同步「关于」页的 `AppVersionLong` 展示(源码用编译期常量 `AppBase.AppVersionLong`,Web 端改为读 `package.json.version`)。
补充说明:ClassIsland 的「关于」页还会展示更新日志、隐私政策与致谢名单,这些内容都是随包分发的 Markdown 文档。实现时不得改为在线拉取——教室环境常常断网,关于页必须在离线时完整可读。更新日志与隐私政策的内容以 `Assets/Documents/` 下的文件为准,发版时同步更新,不允许只改版本号不改日志。
### 15.12 验收标准
1. **完整性**:本节列出的资源 100% 存在于仓库;用脚本比对清单与文件,缺一项即失败(允许同一资源用等价格式替换,但必须在清单中登记变更)。
2. **图标**:`electron-builder` 打包后 Windows exe/installer、Linux AppImage、macOS icns 三端图标均正确;ICO 内嵌 6 档尺寸;任务栏/开始菜单/关于页三处图标一致。
3. **字体**:断网启动,界面仍显示 HarmonyOS Sans SC(非回退字体);图标字体全部可渲染(抽查 Fluent/Lucide/SF 各 3 个码位);`document.fonts.check()` 对 4 个正文字重与 3 个图标族返回 true。
4. **字体许可**:安装包内包含 `fonts/LICENSE.txt`(HarmonyOS 许可)与 `licenses.json`;「关于 → 许可」页可查看并可滚动到底。
5. **音效**:默认配置下提醒有声音;把音量调到 0 静音;自定义音效路径失效时回落内置 1.wav 且不崩溃;同一条提醒只响一次。
6. **天气图标**:4 套模板均可切换且立即生效;40 个天气代码逐个渲染正确(截图对比名称与图标);未知代码 99 显示「未知」图标。
7. **贴纸**:`sticker(帕姆_嗨)` 在教程中正确显示;22 张贴纸全部可加载(无 404);比例不变形。
8. **教程**:`classisland.getStarted` 三个教程组可完整播放到结束;跳过后再次进入从第一步开始;教程图片无拉伸、无破图。
9. **本地化**:切换 en/zh-Hans/zh-Hant 后设置页与托盘菜单文案切换且立即生效;日期格式随之变化;其余页面若无翻译必须回落中文而不是显示 key。
10. **离线**:在完全断网、无缓存的干净环境中启动,所有资源(字体/图标/音效/贴纸/教程图)均本地可用,控制台无对外请求(除用户主动触发的天气/更新功能)。
11. **体积**:字体 + 图标 + 音效 + 贴纸 + 教程图的总增量不超过 30MB 打包后体积;超过时必须说明取舍(例如贴纸按需下载,但 ClassIsland 的语义是离线可用,默认应全量内置)。