Improve Android app UI and controller flows

This commit is contained in:
2026-10-09 16:43:58 +08:00
parent c0e26b97fe
commit 608229a497
90 changed files with 8103 additions and 1133 deletions
+69 -44
View File
@@ -15,7 +15,11 @@
| `WEB-ENTRY` | 网页入口和整体页面 | 局域网设备访问移动端优先的控制面板,首页直接进入可操作界面。 |
| `WEB-WORKSPACES` | 可扩展工作区和导航 | 工作区通过注册信息生成单层侧栏和 URL hash;用户可在内存草稿中上移、下移并显式保存设备共享顺序。 |
| `WEB-PREVIEW` | 共享正向预览与设备监视器 | 普通编辑工作区共用页面顶部的逻辑 `0°` 组合画板;设备状态、系统设置和模板管理在同一位置显示当前设备逻辑帧的只读监视画面。 |
| `WEB-COMPOSITION` | 统一场景与图层合成 | 像素层固定在最底部,有序元素依次叠加;设备测试独占覆盖但不得销毁场景草稿。 |
| `WEB-COMPOSITION` | 统一场景与图层合成 | 有序画笔和多文字图层依次覆盖;中央64×64输出,设备测试不得销毁草稿。 |
| `WEB-LAYERS` | 多图层编辑与复制 | 至少一个画笔层,文字层多元素;置顶复制、命名、排序及跨内容追加。 |
| `WEB-EXTENDED-CANVAS` | 可切换192画布与整层移动 | 扩展显示按浏览器记忆,偏移±64,视线和图层移动分离。 |
| `WEB-LAYER-OVERFLOW` | 越界确认与永久裁切 | 确认前不保存,取消恢复,背景不报警;文字裁切持久化且可撤销。 |
| `CONFIG-SCENE-V2` | 场景及内容迁移 | scene v2、模板v2、动图v3、配置v11;摘要校验和安全迁移。 |
| `WEB-BACKEND` | FastAPI、REST、WebSocket、静态文件托管 | 服务监听 `0.0.0.0:8080`,页面通过 API/WS 调用显示服务。 |
| `WEB-STARTUP-INDICATOR` | 开机运行指示兼容资源 | 旧开机笑脸不再作为独立启动覆盖层;其两态像素资源继续供只读演示案例和默认演示动图复用。 |
| `WEB-DEFAULT-DISPLAY` | 默认显示内容 | 模板管理可把演示案例、用户静态模板或非空用户动图设为默认;开机和启动提示结束后显示该内容,失效时回退演示动图。 |
@@ -58,7 +62,7 @@
| `WEB-TEXT-I18N` | 多语言静态文字 | `default` 自动选择能覆盖全文的字体,支持常见现代语言且不以缺字方框代替失败。 |
| `WEB-TEXT-FONTS` | 字体选择与导入 | 文字编辑器使用可搜索的设备字体目录,允许导入受校验的字体文件且不要求用户输入服务器路径。 |
| `WEB-TEMPLATES` | 可编辑场景模板 | 内容工作区可保存或更新完整场景模板;模板管理统一提供播放、编辑、复制、重命名、删除和混合排序,动图卡片按完整帧序列动态预览,播放与编辑草稿互不影响;动态预览与动图管理共享设备配置的并发上限。 |
| `WEB-ANIMATIONS` | 动图文件夹与逐帧编辑 | 把有序 scene v1 帧按独立间隔循环播放;网页负责文件夹、帧顺序、逐帧编辑、复制目标和播放入口,卡片名称单行省略并提供非触摸悬停全名,缩略图按完整帧序列动态预览;动态预览与模板管理共享设备配置的并发上限。 |
| `WEB-ANIMATIONS` | 动图文件夹与逐帧编辑 | 把有序 scene v2 帧按独立间隔循环播放;网页负责文件夹、帧顺序、逐帧编辑、复制目标和播放入口,卡片名称单行省略并提供非触摸悬停全名,缩略图按完整帧序列动态预览;动态预览与模板管理共享设备配置的并发上限。 |
| `WEB-MEDIA-IMPORT` | 媒体内容转换 | 流式导入常见图片、动图和视频,在设备后台统一裁切、缩放、透明合成和逐帧转换为静态模板或动图。 |
| `WEB-API` | REST/WS 契约 | 定义 `/api/status`、`/api/config`、`/api/display/*`、`/api/preview/*`、`/ws/canvas`,包括带会话防护的活动动图运行时控制。 |
| `CONFIG-DATA-LIFECYCLE` | 持久、可再生、运行期与更新暂存数据 | 生产持久根固定为 `/var/lib/matrix-screen-controller`,运行根固定为 `/run/matrix-screen-controller`;格式只向唯一当前 schema 迁移,失败时保留原件并拒绝启动。 |
@@ -68,8 +72,8 @@
| `CONFIG-FRP` | FRP 配置目录 | 持久根 `frp/` 以严格 v1 目录保存多个 UUID 配置和唯一选中项;默认无配置、服务关闭,损坏时保留原件并只关闭 FRP 子系统。 |
| `CONFIG-PREVIEW-REFRESH` | 当前帧监视刷新间隔 | 按设备保存 `preview_refresh_interval_ms`,默认 `1000ms`;允许 `1..60000ms`,低于 `100ms` 时提示负载风险但不阻止保存。 |
| `CONFIG-UI-STATE` | 浏览器场景草稿与编辑工具状态 | 场景使用稳定键 `matrixController:scene`;编辑工具使用独立带版本键,并兼容迁移已有画布、文字和工具状态。 |
| `CONFIG-TEMPLATES` | 核桃派模板持久化 | 完整 scene v1 和有效后端缩略图保存在持久根的 `templates/`;部署、重启和一般清理不得删除。 |
| `CONFIG-ANIMATIONS` | 核桃派动图持久化 | 动图 v2 元数据、独立 scene v1 帧和有效缩略图保存在持久根的 `animations/`;播放按不可变快照懒加载,升级不得删除。 |
| `CONFIG-TEMPLATES` | 核桃派模板持久化 | 完整 scene v2 和有效后端缩略图保存在持久根的 `templates/`;部署、重启和一般清理不得删除。 |
| `CONFIG-ANIMATIONS` | 核桃派动图持久化 | 动图 v3 元数据、独立 scene v2 帧和有效缩略图保存在持久根的 `animations/`;播放按不可变快照懒加载,升级不得删除。 |
| `CONFIG-MEDIA-JOBS` | 媒体转换任务 | 持久根保存活动任务、源文件、预览和暂存输出;成功或取消立即清理,失败与待设置任务最多保留 24 小时。 |
| `CONFIG-FONTS` | 用户导入字体持久化 | 导入字体按内容摘要保存在持久根的 `fonts/`,重启、更新、回滚和一般清理不得删除。 |
| `CONFIG-LIBRARY-ORDER` | 模板管理混合顺序 | 用户静态模板和用户动图的统一顺序保存在持久根的 `library/order.json` v1;演示案例不进入记录。 |
@@ -81,7 +85,7 @@
| `CONFIG-DEFAULT-CONTENT` | 默认显示内容引用 | 配置 v6 严格保存 `{type,id}`,只引用静态模板或非空动图;v5 升级默认引用只读“演示动图”。 |
| `CONFIG-WORKSPACE-ORDER` | 设备共享工作区顺序 | 配置 v7 严格保存唯一工作区 ID 数组;保存后跨浏览器和重启生效,未保存编辑不持久化。 |
| `CONFIG-PERFORMANCE-MODE` | CPU 性能模式请求 | 配置 v9 严格保存布尔字段 `performance_mode_enabled`,v8 升级与新设备均默认关闭;请求状态与实际 governor 分开报告。 |
| `CONFIG-ANIMATION-PREVIEW-CONCURRENCY` | 动态缩略图并发上限 | 配置 v10 严格保存整数 `animation_preview_max_concurrent`,v9 升级与新设备均默认 `2`,只允许 `1..50`;系统设置在性能模式下方保存该值,并明确提示高并发会造成严重性能问题。 |
| `CONFIG-ANIMATION-PREVIEW-CONCURRENCY` | 动态缩略图并发上限 | 配置 v11严格保存整数(v10引入) `animation_preview_max_concurrent`,v9 升级与新设备均默认 `2`,只允许 `1..50`;系统设置在性能模式下方保存该值,并明确提示高并发会造成严重性能问题。 |
| `DEPLOY-KERNEL-ROLLBACK` | AXP313A 候选内核与自动回滚 | 已验证候选以带摘要的预编译离线载荷交付;原内核、DTB、模块和 boot 脚本保持可启动,未通过内核、cpufreq、服务和 GPIO 健康检查时下一次自动回到原内核。 |
| `DEPLOY-OTA-KERNEL-RECOVERY` | OTA 内核能力守护与轻量恢复 | OTA 前后比较内核、cpufreq、性能模式和候选启动标记;正常能力退化时回滚应用。已回退设备可更新应用,只有本机候选内核、DTB、模块及回滚设施通过固定摘要校验时,更新完成后才独立重启尝试恢复一次;失败不得自动重试,缺失或损坏材料只报告需要专用修复包,普通 OTA 不携带内核归档。 |
| `DEPLOY-MEDIA-DECODERS` | 媒体解码依赖与隔离 | Debian 提供 FFmpeg/ffprobe/libheif;独立转换 unit 限制 CPU、内存、IO、设备和网络访问。 |
@@ -159,7 +163,7 @@
- `GET /api/status` 提供应用版本、当前服务实例标识和设备状态修订号;成功改变显示帧、方向或亮度时修订号递增,只读与预览请求不得递增。
- 页面可见时每 5 秒读取一次状态,重新获得焦点时立即读取;检测到另一页面改变实屏状态时更新模式、方向和亮度展示并提示,但不得自动覆盖或发送本地画板。
- 检测到应用版本变化后持续提示刷新;本地画板编辑和导出仍可用,但旧页面不得继续提交设备、配置、色板、模板或 WebSocket 写操作。
- 不同浏览器或设备的 scene v1 草稿继续相互独立。相同来源的多个标签页写入同一草稿时,收到 `storage` 变化的标签页必须暂停继续持久化,并让用户明确选择载入外部草稿或以当前草稿覆盖。
- 不同浏览器或设备的 scene v2 草稿继续相互独立。相同来源的多个标签页写入同一草稿时,收到 `storage` 变化的标签页必须暂停继续持久化,并让用户明确选择载入外部草稿或以当前草稿覆盖。
- 共享物理屏幕仍采用最后一次成功命令生效,不引入用户账户、编辑锁或实时协作画板。
`WEB-CURRENT-DISPLAY` 把顶栏当前画面改为可聚焦按钮。点击后使用原生对话框读取 `GET /api/display/current-frame`:静态模板、未保存内容和系统覆盖只显示当前逻辑帧,点击预览任意位置、遮罩或按 `Escape` 关闭;活动动图显示同一预览、整段循环进度、播放/暂停以及 `0.5x/1x/1.5x/2x` 四档倍速。动图对话框只允许遮罩、关闭按钮或 `Escape` 关闭,操作控件不得误触关闭。
@@ -365,10 +369,22 @@ WantedBy=multi-user.target
### 2.1.2 统一场景合成(`WEB-COMPOSITION`)
`WEB-LAYERS`:scene v2 使用有序画笔/文字图层,至少一个画笔层;每个文字层包含多个文字元素。画图页清空按钮下提供新建、删除、复制、命名、上移和下移,移除独立文字导航。默认图层名称依次编号,新建及复制置顶。画笔空白透出下层,黑色笔迹遮挡;各画笔层可独立开启192×192背景,橡皮和清空仅移除笔迹,文字层无背景。
`WEB-EXTENDED-CANVAS`:素材和编辑边界为192×192(-64..127),输出仅中央64×64(0..63)。编辑小圆球提供默认关闭、本浏览器记忆的扩展显示开关及移动当前层入口;移动提供X/Y输入、各轴±1/±10步进和拖动,偏移限于-64..64,保留视线平移缩放。显示扩展区或移动时标注实际屏幕边框。
`WEB-LAYERS` UI验收:画笔/背景颜色使用对齐的标题行和颜色按钮,桌面并列、窄屏上下排列;背景开关及复制目标帧复选框不得继承普通文本输入框的全宽与48px高度。标签整体可点选,长帧名称换行。复制及脏目标确认弹窗使用不透明表面背景,列表独立滚动,窄屏无横向溢出且操作按钮可达。
`WEB-EXTENDED-CANVAS` 模式退出:偏移面板顶部提供“退出图层移动”,切换到视线模式后仍可操作。退出仅返回当前画笔/文字编辑,保留全屏、扩展显示及视线位置,隐藏偏移面板;已提交位移保留,未提交拖动预览取消,不增减撤销历史。图层移动时“继续编辑”必须可用,不能误提示已经绘画。
`WEB-LAYER-OVERFLOW`:移动整层或文字后,有非背景可见笔迹超出192边界则在提交前确认;取消恢复,确定清除越界笔迹,部分文字累计裁切、整段越界删除。裁切随对象移动/缩放并持久化,移回不恢复;操作可作为一次会话撤销,最多50步,提交成功清空。背景及仅超出实际64屏幕不触发警告。
`CONFIG-SCENE-V2`:旧场景迁移为一个画笔层,有文字时额外一个文字层,中央输出保持一致。模板schema v2、动图schema v3、配置v11移除text导航;坏数据/未知字段/未来版本保全。画笔RGBA以PNG压缩持久化。导入静态一个画笔层,动图/视频逐帧一个画笔层。复制当前画板或已有模板/动图选定帧,副本独立并置顶;跨内容追加使用If-Match,批量动图索引一次提交,失败原帧不变。文字预览可选192尺寸,默认64;驱动RGB888及手机协议不变。
- 场景模型不得依赖 DOM,固定包含一个 `64x64 RGB888` 像素底层和一个有序 `elements` 数组;数组从前到后绘制,后面的元素覆盖前面的元素。
- 像素底层始终位于最底部。文字元素使用独立 `64x64 RGBA` 图层,透明区域必须保留下方像素和其他元素。
- 新建或复制的元素追加到数组末尾并置顶;当前阶段不提供手动前移或后移。
- 每个元素具有稳定 `id`,运行时另有递增修订号。透明层缓存以元素 `id + revision` 识别,旧请求晚于新请求返回时必须丢弃,不能覆盖当前元素;修订号是缓存状态,不属于 scene v1 持久化字段。
- 画笔运行时使用192×192 RGBA,持久化为压缩PNG;文字渲染使用192×192透明层,并在最终合成时取中央区域。透明区域露出下层,黑色笔迹遮挡下层。
- 新建或复制图层追加到末尾、置顶并选中;图层可上下排序,重排不改名称。默认名称取当前未占用的最小图层编号。
- 每个元素具有稳定 `id`,运行时另有递增修订号。透明层缓存以元素 `id + revision` 识别,旧请求晚于新请求返回时必须丢弃,不能覆盖当前元素;全场景元素ID唯一,所属层和裁切参与签名;修订号不持久化。
- 元素存在待渲染或渲染失败状态时,页面必须明确提示并禁用“应用统一画板”,不得提交缺少该元素的不完整帧。
- 场景最终合成为单张 `64x64 RGB` 帧后再交给 `DisplayService`;显示底层不保存、选择或编辑单个元素。
- 后续动画、图片、时钟、天气等普通内容功能必须注册为新的元素或图层提供者,并参与同一有序合成;不得新增直接覆盖屏幕且无法与现有内容叠加的普通显示路径。
@@ -376,8 +392,8 @@ WantedBy=multi-user.target
### 2.1.3 模板管理(`WEB-TEMPLATES`、`WEB-DEMO-TEMPLATES`)
- 工作区注册信息可以声明“支持保存场景模板”;当前像素画布和文字显示声明该能力,后续内容工作区声明后自动出现同一个“保存为模板”入口。
- 保存内容必须是完整、可编辑的 scene v1,保留像素底层、有序元素、稳定元素 ID 和层叠顺序;不得只保存合成 PNG,也不得保存运行时 revision、选择、请求状态或图层缓存。
- 工作区注册信息可以声明“支持保存场景模板”;画图工作区声明该能力,后续内容工作区声明后自动出现同一个“保存为模板”入口。
- 保存内容必须是完整、可编辑的 scene v2,保留图层、偏移、PNG笔迹、背景、文字裁切和稳定ID;不得只保存合成 PNG,也不得保存运行时 revision、选择、请求状态或图层缓存。
- 保存时输入 `1..80` 个字符的模板名称;忽略首尾空白并按 Unicode 大小写不敏感规则保持唯一,重名不得覆盖已有模板。
- 从动图帧编辑上下文点击“保存为模板”时,名称弹窗必须在“保存为模板”标题右侧显示“当前帧将被保存为一个静态图模板”;普通场景保存以及共享弹窗用于新建、重命名时不得显示或残留该提示。
- 左侧栏新增“模板管理”。模板使用购物软件式响应式卡片网格:正方形缩略图在上、名称在下,并显示占用空间;手机默认两列,宽屏自动增加列数。静态模板和动图统一使用两列四行操作:第一行“播放、编辑”,第二行“复制、重命名”,第三行横跨两列显示“删除”,第四行“上移、下移”。默认内容选择模式可以在上述常态操作后额外显示单列“设为默认”。
@@ -395,7 +411,7 @@ WantedBy=multi-user.target
### 2.1.4 动图管理(`WEB-ANIMATIONS`、`CONFIG-ANIMATIONS`)
- 单层侧栏中动图管理的默认位置在文字显示之后、模板管理之前;保存自定义工作区顺序后允许改变该位置。一个动图是带稳定 UUID、名称和修订值的文件夹,内部保存按顺序排列的完整 scene v1 帧。
- 单层侧栏中动图管理的默认位置在媒体转换之后、模板管理之前;保存自定义工作区顺序后允许改变该位置。一个动图是带稳定 UUID、名称和修订值的文件夹,内部保存按顺序排列的完整 scene v2 帧。
- 动图管理页面内容顺序固定为“新建动图及从当前画板新建帧操作行、当前打开动图的帧卡片和单帧时长区、已有动图列表”。用户界面统一使用“动图”称呼;持久实现仍可把一个动图保存为带稳定 UUID、名称和修订值的文件夹。
- 已有动图卡片在名称上方显示正方形动态缩略图。名称固定单行尾部省略,任何中文、英文或无空格长名称都不得撑宽网格;完整名称只在重命名输入框以及确实发生截断时的细指针鼠标悬停提示中显示,触摸、点击和长按不得展开名称。
- 服务启动时对动图元数据、scene 与缩略图完成严格校验后,必须复用同一批已校验记录建立首次列表缓存;首次 `GET /api/animations` 不得再次遍历和校验全部帧文件。任一动图写入后缓存失效并按当前持久数据重建,REST 响应字段和错误语义不变。
@@ -404,7 +420,7 @@ WantedBy=multi-user.target
- 时长输入在用户键入过程中不校验、不提交,只在失焦、按 Enter 或 `change` 时校验;非法值保留并显示字段错误,不调用 API。时长数字必须能用鼠标或触摸长按选择且不得触发拖动,全部交互控件及其 `8 CSS px` 保护区遵守 `WEB-INTERACTION-FEEDBACK`。
- 帧列表上方固定提供批量复制、批量移动和批量删除。勾选任意帧即进入选择模式:复选框、单位、时长、复制到已选帧和三个批量入口保持可用,拖动、编辑、重命名、上下移、单帧复制/删除以及切换动图或上下文的操作显示明确不可用原因。修改任意时长或复制时长到已选帧前必须二次确认;取消不发送请求并恢复发起输入,确认后原子应用到全部已选帧。批量时长成功后保留选择;复制、移动或删除成功后清空选择。
- 批量移动仅限当前动图,保持所选帧当前相对顺序,只能在弹窗中选择“插入到最前”或某个未选帧之后;已选帧在目标下拉中以黑色不可用项显示。批量复制先选择当前或其他普通动图,再复用相同位置选择,但复制目标不因来源已选而禁用。普通单帧复制为动图时也必须选择插入位置,复制为静态模板时保持现有流程。批量删除二次确认后允许留下空动图。
- 点击“编辑此帧”进入独立编辑上下文,普通浏览器 scene 草稿保持不变。像素画布和文字显示共同编辑该帧,并在“合成预览”右侧只显示一处编辑注释和已保存/尚未保存状态;自动帧为“动图名-第N帧”,自定义帧为“动图名-自定义帧名”,不得重复动图名。该注释不得出现在其他工作区;正在编辑的帧卡片同步高亮,顶部主按钮改为“保存当前动图帧”,保存不改变实屏,保存后继续编辑并刷新缩略图。
- 点击“编辑此帧”进入独立编辑上下文,普通浏览器 scene 草稿保持不变。画图工作区内的画笔和文字图层共同编辑该帧,并在“合成预览”右侧只显示一处编辑注释和已保存/尚未保存状态;自动帧为“动图名-第N帧”,自定义帧为“动图名-自定义帧名”,不得重复动图名。该注释不得出现在其他工作区;正在编辑的帧卡片同步高亮,顶部主按钮改为“保存当前动图帧”,保存不改变实屏,保存后继续编辑并刷新缩略图。
- 切换帧、打开其他动图、退出动图编辑、载入模板或外部浏览器草稿以及其他会替换当前画板的操作,必须先经过同一个未保存修改守卫。存在修改时提供“应用修改、否并放弃修改、取消”;保存失败或修订冲突必须取消后续操作并保留本页画面。刷新或关闭页面时仍有未保存帧修改则触发浏览器离开提示。
- 模板管理同时显示带“静态”或“动图”标记的卡片。动图卡片先显示第一帧,再在完整时间表就绪后按全部帧和原时长循环,并显示帧数、总时长和空间;空动图显示明确占位且不可播放。静态模板和单帧复制必须弹出目标选择,可深复制为静态模板或追加到指定动图。
- 动图卡片提供整项深复制;普通动图与演示动图复制后都生成包含全体帧、顺序、名称和时长的独立普通动图。
@@ -564,17 +580,17 @@ WebSocket 消息示例:
- 画布和文字都受同一方向规则影响。
- 后续新增任何显示功能,都不需要重新实现方向逻辑。
### 2.5 文字显示(`WEB-TEXT`、`WEB-TEXT-I18N`、`WEB-TEXT-FONTS`)
### 2.5 文字图层(`WEB-TEXT`、`WEB-TEXT-I18N`、`WEB-TEXT-FONTS`)
目标:允许用户在统一场景中创建多组互相独立、可叠加的静态文字元素。
页面功能:
- 文字工作区提供元素列表,以及“新建文字”“复制”“删除”按钮;点击画板文字或列表项后切换当前选中元素。
- 选中文字图层时,上方工具区提供该层的元素列表,以及“新建文字”“复制”“删除”按钮;点击画板文字或列表项后切换当前选中元素。
- 现有文本、字体、字号、文字颜色、`x` / `y` 坐标和左/中/右对齐编辑器始终绑定当前选中元素,选中变化时立即显示该元素的值。
- “新建文字”创建内容为小写 `ok` 的元素,使用配置中的默认字体和字号、白色文字并默认位于画板中央;新元素追加到场景顶层并自动选中。
- “复制”创建新 `id`,复制当前元素属性,将 `x` 和 `y` 各偏移 `2` 个逻辑像素,追加到顶层并选中新副本;超出边界的部分沿用裁切规则。
- “删除”只删除当前元素,不影响像素底层或其他元素;没有选中元素时复制和删除按钮禁用。
- “新建文字”创建内容为小写 `ok` 的元素,使用配置中的默认字体和字号、白色文字并默认位于画板中央;新元素追加到当前文字层末尾并自动选中。
- “复制”创建新 `id`,复制当前元素属性,将 `x` 和 `y` 各偏移 `2` 个逻辑像素,追加到顶层并选中新副本;复制保留裁切约束。
- “删除”只删除当前元素,不影响其他图层或元素;没有选中元素时复制和删除按钮禁用。
- 每个文字元素只包含文字本身,不提供背景颜色或全帧背景字段。
- 画板上的文字可用 Pointer Events 拖动;选中框角点提供类似演示文稿文本框的等比缩放,缩放只改变字号,不增加自由宽高或自动换行。
- 拖动和缩放过程中使用已缓存的透明层做连续视觉变换;交互结束后提交整数 `x`、`y` 和 `1..64` 的整数字号,再调用后端 Pillow 刷新精确图层。
@@ -589,7 +605,7 @@ WebSocket 消息示例:
后端行为:
- `POST /api/preview/text-layer` 用 Pillow 生成一张 `64x64 RGBA` 透明图层,不调用显示驱动。
- `POST /api/preview/text-layer` 用 Pillow 生成透明图层,`edit_size` 可选64或192(默认64),不调用显示驱动。
- 使用 `ImageDraw.text()` 绘制文字,透明区域 alpha 为 `0`,文字颜色区域保留有效 alpha。
- 使用 `ImageFont.truetype()` 加载字体;没有指定字体时使用默认字体。
- `font:"default"` 表示自动多语言字体,不再表示某一个固定英文字体。渲染器必须选择一张能覆盖当前完整文本的字体,以保留复杂文字塑形和双向排版。
@@ -776,7 +792,9 @@ WebSocket 消息示例:
"voltage_calibrated_at": null,
"voltage_calibration_reference": null,
"voltage_calibration_uncalibrated": null,
"workspace_order": ["device", "settings", "canvas", "text", "animations", "templates"]
"workspace_order": ["device", "settings", "canvas", "media-import", "animations", "templates"],
"performance_mode_enabled": false,
"animation_preview_max_concurrent": 2
}
```
@@ -793,7 +811,9 @@ WebSocket 消息示例:
"default_font": "default",
"default_text_size": 12,
"low_voltage_protection_enabled": true,
"workspace_order": ["device", "settings", "canvas", "text", "animations", "templates"]
"workspace_order": ["device", "settings", "canvas", "media-import", "animations", "templates"],
"performance_mode_enabled": false,
"animation_preview_max_concurrent": 2
}
```
@@ -1070,7 +1090,7 @@ WebSocket 消息示例:
```json
{
"schema_version": 7,
"schema_version": 11,
"orientation": 0,
"brightness": 40,
"default_font": "default",
@@ -1089,7 +1109,9 @@ WebSocket 消息示例:
"type": "animation",
"id": "00000000-0000-4000-8000-000000000102"
},
"workspace_order": ["device", "settings", "canvas", "text", "animations", "templates"]
"workspace_order": ["device", "settings", "canvas", "media-import", "animations", "templates"],
"performance_mode_enabled": false,
"animation_preview_max_concurrent": 2
}
```
@@ -1098,7 +1120,7 @@ WebSocket 消息示例:
- 写入 JSON 时使用 UTF-8。
- 配置文件确实不存在时才创建当前 schema 的默认配置;已存在文件不能因读取、迁移或校验失败被默认值替换。
- 缺少 `schema_version` 的现有格式只按 legacy v0 处理;存储层通过登记的 `vN → vN+1` 函数逐级迁移,全部步骤和当前 schema 校验成功后才写回。业务层只接收当前格式,不保留多版本分支。
- 配置字段集必须按版本显式维护:v1 是原有方向、亮度、字体、模式、色板与四个电压校准字段;v2 增加 `preview_refresh_interval_ms`;v3 增加严格布尔字段 `low_voltage_protection_enabled`;v4 增加 `matrix_refresh_rate_limit_hz`;v5 增加严格大写 `#RRGGBB` 字段 `custom_test_color`;v6 增加 `default_display`;当前 v7 增加 `workspace_order`。逐级迁移分别只增加对应默认值并完整保留已有业务值;模板当前 schema 仍为 v1,不随配置版本同步升级。
- 配置字段集必须按版本显式维护:v1 是原有方向、亮度、字体、模式、色板与四个电压校准字段;v2 增加 `preview_refresh_interval_ms`;v3 增加严格布尔字段 `low_voltage_protection_enabled`;v4 增加 `matrix_refresh_rate_limit_hz`;v5 增加严格大写 `#RRGGBB` 字段 `custom_test_color`;v6 增加 `default_display`;v7增加 `workspace_order`,v8插入媒体转换,v9增加性能模式,v10增加动图预览并发,v11仅移除导航中的 `text` 并保留其余顺序;旧 `#text` 入口跳转画图页。模板当前schema v2,动图v3。
- 损坏 JSON、布尔值冒充数值、未知字段、未知更高版本或无法安全迁移时,保持原文件字节不变、记录明确错误并阻止服务启动,不得跳过字段、猜测修复或自动另建配置。
- 写入前校验当前 schema 的完整字段集合和范围。电压校准系数必须是 `0.8..1.2` 的有限数值;四个校准字段作为一组校验,缺失或不一致时属于无效现有配置,不能静默回落为未校准状态。
- 所有配置和模板写入共用耐久原子写入:在目标同目录创建临时文件,写完后刷新并 `fsync` 文件,使用 `os.replace` 替换,再同步父目录;任一步失败都清理本次临时文件并保留旧文件,不累计滚动备份。
@@ -1128,39 +1150,31 @@ WebSocket 消息示例:
```json
{
"version": 1,
"width": 64,
"height": 64,
"pixelRgb": "<base64 RGB888>",
"elements": [
{
"id": "<stable id>",
"type": "text",
"text": "ok",
"font": "default",
"size": 12,
"x": 4,
"y": 24,
"align": "left",
"color": "#FFFFFF"
}
"version": 2, "width": 64, "height": 64,
"layers": [
{"id": "layer-1", "name": "图层1", "type": "brush", "x": 0, "y": 0,
"background": null, "backgroundColor": "#000000", "pixelPng": "<base64 compressed 192×192 RGBA PNG>"},
{"id": "layer-2", "name": "图层2", "type": "text", "x": 0, "y": 0,
"elements": [{"id": "text-1", "type": "text", "text": "ok", "font": "default",
"size": 12, "x": 32, "y": 26, "align": "center", "color": "#FFFFFF", "clip": null}]}
]
}
```
- `pixelRgb` 解码后必须正好是 `64 * 64 * 3` 字节 RGB888;`elements` 数组顺序就是从底到顶的绘制顺序。文字元素只持久化示例所列字段,不得保存 `background`、运行时 `revision`、渲染状态或图层缓存。
- `layers` 从底到顶,ID唯一,至少一个画笔层;层偏移为−64..64整数。文字元素ID全场景唯一,坐标、大小沿用原范围。`clip` 为null或相对文字锚点、以字号为单位的 `[left, top, right, bottom]` 矩形;累计交集永久保留,随锚点和字号变换。图层和文字只保存已列字段。旧v1先严格校验,再把中央RGB写入一个画笔层,全部旧文字写入一个上方文字层,外围为空白。
- 整层拖动松手、单段位置拖动松手、位置输入回车/失焦和每次步进均为一次提交;候选越界先确认,确认前不得写草稿、保存或应用。背景不计入越界;确认裁切和位置变化是一个撤销步骤,最多50步。
- 选中元素、渲染中/失败状态、透明 PNG 缓存、状态消息、设备状态、测试选择和错误不持久化。
- 稳定键不存在时,先读取并验证所有实际存在的旧键;任一旧键损坏或无法识别都必须保留全部原值并停止迁移,不能跳过高优先级损坏值后拿低优先级草稿覆盖。全部验证通过后,先迁移现有 `matrixController:scene:v1`;没有该键时再按 `matrixController:canvas:v3`、`matrixController:canvas:v2`、旧 `matrixCanvasRgb` 的优先顺序选择像素草稿,同时独立读取 `matrixController:text:v1` 并合并为文字元素。迁移保留能验证的旧像素、画笔/背景颜色、画笔粗细及文字属性,丢弃旧文字背景。
- 旧文字草稿迁移为一个稳定 `id` 的 `type:"text"` 元素;损坏文字元素单独跳过,不能连带清空有效像素或其他元素。缺少画笔粗细时回落为 `1`。
- 只有新内容已完整校验并成功写入稳定键后,才精确删除本次已迁移的旧键;写入失败时旧键和值必须保留。
- 稳定键内容损坏、出现未知更高版本或迁移失败时,页面保留原值和内存草稿、停止自动写回并明确提示用户;不得用空白场景覆盖,不得自动上传到核桃派。场景只保存在当前浏览器,不写入设备 `config.json`,不要求跨浏览器共享,也不保证核桃派重启后自动恢复实屏。
- 同一来源的其他标签页修改稳定场景键时不得直接替换当前内存草稿;冲突解决前当前标签页的后续编辑继续保留在内存但暂停写回 `localStorage`。用户选择“载入其他标签草稿”后采用最后收到的有效外部值,选择“保留当前草稿”后才显式覆盖共享键。
- 画笔颜色、像素层背景颜色、画笔模式、两种模式各自的笔尖粗细、当前画笔工具和坐标系开关使用独立带版本号的本地 UI 状态;它们不是场景元素,也不改变 scene v1 的最终像素和元素契约。当前键为 `matrixController:canvas-tools:v3`:刷新后恢复模式、两套尺寸和坐标系选择;首次从 v2/v1 读取时保留已有工具值、把旧 `brushSize` 迁入普通模式,像素模式默认 `1x1` 且默认关闭,坐标系默认关闭,损坏或缺失值安全回落到默认值。
- 每个新工作区显式选择 `none`、`local` 或 `server`;普通显示功能必须说明怎样接入 scene v1,不得把未来场景大对象无条件塞入服务端配置。
- 画笔颜色、像素层背景颜色、画笔模式、两种模式各自的笔尖粗细、当前画笔工具和坐标系开关使用独立带版本号的本地 UI 状态;它们不是场景元素,扩展显示开关同样仅属于浏览器工具状态。当前键为 `matrixController:canvas-tools:v3`:刷新后恢复模式、两套尺寸和坐标系选择;首次从 v2/v1 读取时保留已有工具值、把旧 `brushSize` 迁入普通模式,像素模式默认 `1x1` 且默认关闭,坐标系默认关闭,损坏或缺失值安全回落到默认值。
- 每个新工作区显式选择 `none`、`local` 或 `server`;普通显示功能必须说明怎样接入 scene v2,不得把未来场景大对象无条件塞入服务端配置。
核桃派模板(`CONFIG-TEMPLATES`)使用持久根下独立的 `templates/` 数据区:
- 每个模板 JSON 使用不可变 UUID 文件名,用户名称不参与路径拼接;落盘记录包含仅供存储层使用的 `schema_version: 1`,API 中的模板 ID、名称、创建/修改时间、场景摘要、内容和修订语义保持不变。
- 每个模板 JSON 使用不可变 UUID 文件名,用户名称不参与路径拼接;落盘记录包含仅供存储层使用的 `schema_version: 2`,API 中的模板 ID、名称、创建/修改时间、场景摘要、内容和修订语义保持不变。
- 缺少版本的现有模板按 legacy v0 逐级迁移到唯一当前 schema。服务启动必须先迁移并校验全部模板记录,再执行任何缩略图协调或清理;任一模板损坏、含未知字段、版本过高或迁移失败时,所有原件保持不变并阻止服务启动。
- 缩略图文件名包含模板 UUID 和规范场景内容摘要。更新时先生成并验证新图,再提交模板 JSON,最后删除旧摘要图片;重命名不重复生成内容未变化的缩略图。
- 服务启动和每次模板变更后只在专用缩略图目录内按严格 UUID/摘要规则清理临时文件、孤立图片和过期图片;读取或迁移阶段存在任何不可读记录时不得开始清理,也不得扫描或删除配置、运行期最新帧、模板 JSON 或其他用户数据。
@@ -1244,3 +1258,14 @@ WebSocket 消息示例:
- MDN Canvas API:https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API
- Pillow ImageDraw:https://pillow.readthedocs.io/en/stable/reference/ImageDraw.html
- systemd service:https://manpages.debian.org/bookworm/systemd/systemd.service.5.en.html
### 图层追加接口(`WEB-LAYERS`)
- `POST /api/templates/{id}/layers`:`{layer: <完整图层>}`,要求 `If-Match`,副本独立ID并置顶。
- `POST /api/animations/{id}/frames/layers`:`{layer: <完整图层>, frame_ids: [<稳定帧ID>]}`,要求 `If-Match`;单帧、多选或全部帧共用此接口。全部新场景和缩略图成功后才一次提交索引;失败不改变任何原帧。时长及帧顺序不变。
- 正在编辑的目标有修改时,先保存/放弃/取消;保存失败和冲突停止复制。演示目标只读。
- `/api/preview/text-layer` 新增 `edit_size: 64|192`,默认64;192模式坐标为图像坐标(逻辑坐标加64)。输出仍64×64 RGB888,手机内容库与播放契约不变。
画笔层 `background` 为当前启用的颜色字符串或null(关闭);`backgroundColor` 保存该层在关闭状态下的颜色选择。此已登记可选字段缺省时读取为现有背景颜色或黑色,兼容早期scene v2;新网页保存时包含该值,切层、复制及重载不得借用其他图层颜色。关闭背景不绘制该颜色,擦除/清空/裁切不改变它。
迁移边界:旧导航只有 `text` 时,移除后使用当前默认导航顺序;其余非空顺序保持不变。旧浏览器草稿同样先严格检查字段、整数坐标及范围;未知字段、损坏或未来格式必须保留旧键并禁用覆盖保存,不能由旧宽松读取器丢弃字段后继续迁移。