Files
Genarrative/docs/experience/MOBILE_UI_DEV_EXPERIENCE.md
2026-05-08 11:44:42 +08:00

229 lines
11 KiB
Markdown
Raw Permalink 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.
# 奇幻酒馆 UI 开发经验沉淀
## 1. 总体原则
### 1.1 先保证移动端成立,再兼容网页端
- 入口页、世界选择、角色选择、冒险页、弹窗面板,都要先按手机竖屏去定义信息密度。
- 网页端只做“放宽容器、增加留白、补充 hover”不要反过来让桌面布局压垮手机体验。
- 任何区域如果在移动端需要滚动,必须明确谁滚动,不能让整页和局部同时争夺滚动。
### 1.2 游戏 UI 要优先“状态清晰”,而不是“文案很多”
- 开始页应该像主菜单,不像产品介绍页。
- 角色选择页应该像角色选择器,不像角色说明书。
- 冒险页应该像战斗/剧情操作台,不像文档阅读器。
### 1.3 一屏内的层级顺序要稳定
- 上半部分:画面演出。
- 中间部分:剧情或核心信息。
- 底部:操作按钮。
- 玩家必须能快速判断“我在看什么、下一步点哪里”。
## 2. 入口页经验
### 2.1 开始页
- 极简化是对的。
- 当前实践证明:开始页只保留“开始游戏”和“开发团队”两个主按钮,体验明显更像游戏。
- 游戏名和英文副标题可以保留,但不要再加长段描述。
### 2.2 世界选择
- 纵向焦点轮播比普通列表更适合移动端。
- 当前居中的卡片应该最大、最清晰、最亮;上下卡片缩放和透明度随滚动连续变化。
- 世界确认动作应该绑定当前聚焦卡,而不是每张卡都塞太多按钮。
### 2.3 角色选择
- 横向轮播是正确方向。
- 中间卡片应承担“主视觉 + 主要信息”。
- 左右卡片只做预览,不需要承载完整信息。
- 左右卡片倾斜方向一定要符合透视直觉:
左侧卡片向左外倾,右侧卡片向右外倾。
- 中间卡片不要出现任何模糊,否则会破坏“当前选中”的确认感。
## 3. 角色选择页经验
### 3.1 聚焦卡的表现
- 中间聚焦卡用角色 `run` 动画是有效的,能明显提升“角色活着”的感觉。
- 但动画资源和静态立绘的锚点通常不一致,必须单独做位置与缩放修正。
- 结论:
动画版角色不要直接复用静态图样式,要单独给 `transform``height``transform-origin`
### 3.2 信息区要紧凑
- 角色数值和角色背景应该放在轮播下方,但必须压缩高度。
- 如果下方面板过高,会直接破坏上半部分轮播体验,尤其在手机上。
- 删除背景面板里的额外动画模块是正确的,因为它与主轮播重复抢视觉焦点。
### 3.3 文案层级
- 页面标题只保留一句:
“选择你扮演的角色”
- 不要再强调 `CHARACTER SELECT` 之类的开发向分类标签。
- 聚焦卡下方直接显示角色名,比把名字只放在卡片底部更直观。
### 3.4 按钮位置
- “确认选择”必须放在角色轮播和信息区之后,作为页面最后的主动作。
- 按钮不宜过宽过高,否则会抢轮播的视觉重心。
## 4. 冒险页经验
### 4.1 剧情区必须自适应
- 剧情文本区不应该写死高度。
- 正确做法是:
让它自动填满“上方画面下缘”和“底部按钮区上缘”之间的剩余空间。
- 这样才能同时保证:
1. 上方画面一屏可见
2. 下方三个选项一屏可见
3. 中间剧情尽量大
### 4.2 底部操作区必须锚定到底
- 队伍、背包、换一换、选项列表,都应该属于底部控制区。
- 用户会天然在屏幕底部寻找交互入口,尤其是手机。
- 因此:
不要把这些按钮漂在中间,不要让剧情区把它们挤走。
### 4.3 队伍与背包不应打断主流程
- 在冒险页内,队伍和背包更适合“弹出面板”而不是“切换整页”。
- 原因:
1. 不会打断当前剧情阅读
2. 用户返回成本更低
3. 操作像手游副面板,更符合预期
### 4.3.1 弹出确认面板不能透明
- 删除作品、发布后分享、确认离开等关键弹窗必须有实体面板底色,不能只靠透明背景、毛玻璃或遮罩承载内容。
- 通过 portal 挂到 `body` 的平台弹窗必须在遮罩层补齐平台主题类,否则主题变量会脱离页面容器,轻则颜色漂移,重则面板背景看起来透明。
- 移动端关键确认弹窗优先居中显示,并保留 `max-height + 内部滚动`,避免被底部导航、安全区或底部抽屉布局遮住。
### 4.4 图标优于文字按钮
- 在底部工具区,队伍/背包改成 icon 后更紧凑。
- 但必须保留 `aria-label`,保证语义清晰、后续也方便测试。
### 4.5 冒险主场景不要挂右上角账号悬浮条
- 冒险页右上角属于画面演出和战斗/剧情信息的高频观察区。
- 全局账号信息条挂在这里,会直接压住场景、敌人血条或顶部提示,手机端尤其明显。
- 结论:
账号入口应收回平台首页、个人页或设置面板,不要在实际冒险主场景常驻悬浮显示。
- 当前仓库已进一步收口为:
不再提供右上角全局账号悬浮条,统一只保留页面内入口与独立账号面板。
### 4.6 冒险主场景双方角色必须按画面中线镜像
- 非滚动画面的交谈、预览、单体对峙态,主角和对面角色不能分别用左右边距、世界坐标和角色宽度重复推算。
- 正确做法是先定义“角色容器中心距离画面中线”的统一间距,再让主角中心落在中线左侧、对面角色中心落在中线右侧。
- 角色容器宽度、角色图片缩放和左右朝向必须各自独立处理,不能用额外 left inset 去修正角色图片,否则会破坏左右对称。
- 自定义图片 NPC、模板角色和组合式 NPC 都要进入同一 112px 场景容器,再按各自素材锚点做场景缩放,保证视觉大小不漂移。
## 5. 队伍面板经验
### 5.1 移动端成员列表不能太“卡片化”
- 如果每个成员都再套一层大边框卡片,手机上会显得很挤。
- 更好的方式是直接在主面板里陈列成员,弱化分隔、强化内容。
### 5.2 队伍列表展示什么
- 头像
- 姓名
- 称号
- 身份标记(领队/同行)
- HP / MP
### 5.3 队伍详情弹窗
- 弹窗必须可滚动。
- 弹窗宽度不宜太大,手机优先单列或偏单列。
- 技能、装备、属性三个区块保持稳定结构,便于扫读。
## 6. 背包页经验
### 6.1 格子数要优先适配手机
- 手机端格子间距要小一号。
- 图标尺寸和分类角标要跟着缩小。
- 目标不是“每个格子信息很多”,而是“单屏能看更多格子”。
### 6.2 背包详情弹窗
- 手机端改成单列/窄宽度布局更合理。
- 详情窗里的信息顺序建议固定:
1. 名称与类别
2. 品质与数量
3. 大图标
4. 说明
5. 标签
## 7. 样式与动画经验
### 7.1 轮播动画要连续,不要离散
- 滚动时应根据“当前位置与当前卡片中心的距离”实时计算:
- `scale`
- `opacity`
- `rotate`
- `translate`
- 不要做成“翻页后才跳变”的效果。
### 7.2 焦点卡与非焦点卡的职责要不同
- 焦点卡负责可读性与确认感。
- 非焦点卡负责预告与空间深度。
- 所以焦点卡不该模糊,非焦点卡可以轻微降透明度、缩放、偏移。
### 7.3 资源锚点要单独校准
- 静态立绘和动画帧经常不是同一锚点。
- 只要切换成动画,就需要重新调:
- 高度
- Y 偏移
- 缩放
- `transform-origin`
## 8. 工程经验
### 8.1 组件要继续拆
- 本轮重构证明,把入口页、冒险页、队伍页、背包页拆成独立组件是正确的。
- 后续新增 UI 需求时,应优先落在:
- `GameShell.tsx`
- `AdventurePanel.tsx`
- `CharacterPanel.tsx`
- `InventoryPanel.tsx`
### 8.2 不要相信“服务已经在跑”
- 这轮出现过“端口上有进程,但浏览器仍然拿到旧模块”的问题。
- 实际经验:
1. 要检查 `src` 文件内容
2. 要检查 dev server 实际返回的模块内容
3. 要确认启动脚本是否是当前项目真正使用的脚本
### 8.3 本项目当前开发服务入口
- 本地正确启动脚本是:
`node scripts/vite-cli.mjs --port=3000 --host=0.0.0.0`
- 历史脚本或旧进程会导致“代码已改但 UI 看起来没变”的假象。
## 9. 后续建议
### 9.1 可以继续统一中英混杂文案
- 当前部分新旧文本仍有历史遗留字符问题。
- 如果后面继续做 UI 精修,建议单独做一轮文案清洗。
### 9.2 可以把轮播抽成通用组件
- 世界纵向焦点轮播
- 角色横向倾斜轮播
- 这两套逻辑已经足够稳定,适合后续抽成通用 hook 或通用组件。
### 9.3 可以补移动端安全区适配
- 当前已经偏移动端优先,但还可以继续加:
- `safe-area-inset-bottom`
- `safe-area-inset-top`
- 更细的竖屏断点处理
## 10. 一句话结论
这一轮最关键的经验是:
**游戏 UI 的移动端优化,本质不是把元素缩小,而是重组视觉重心、固定操作锚点、让焦点内容在一屏内自然成立。**
### 10.1 可扮演角色形象预览保持 1:1
- 可扮演角色的形象预览容器统一使用 1:1 方形,入口选择轮播、角色资产工坊和结果页角色卡片都不能用纵向长卡片去拉伸预览图。
- 预览图片本身使用 `object-contain`,保证 AI 生成主形象、模板像素角色和运行时动画都在方形容器内完整显示,不裁切角色主体。
- 卡片可以在方形预览下方放角色名、称号、状态等信息,但这些文本区不能反向影响预览区比例。
- 编辑角色弹窗也遵循同一规则:移动端不能用固定高度压扁预览区,预览容器应随宽度保持 `aspect-square`
### 10.2 运行画面怪物锚点按视觉底边校准
- 对战预览里主角和对手要沿画面中线成对出现,但纵向不能只共用一个 `bottom` 常量。
- 怪物精灵帧的空白、体型和脚底位置差异很大,运行画面应按帧高分档下沉,让怪物视觉底边落在主角同一条地面线上。
- 后续新增怪物资源时,先检查红圈标注的实际落点,再调整锚点分档或单怪物偏移,避免出现“悬在地面上方”的状态。
- 自定义世界里敌对角色已经先作为场景 NPC 存在,即使它同时携带 `characterId``monsterPresetId`,画布也不能直接沿用模板角色的 `groundOffsetY`;只要 encounter 自身有 `imageSrc``visual`,就按场景 NPC 自定义形象锚点处理。
- 幕预览运行时还会构造“无 `characterId`、但有 `visual` 的场景 NPC”这类和平相遇分支同样必须套用场景 NPC 自定义形象锚点,否则会停在画面中上部。
### 10.3 移动端固定整页画布缩放
- 主站移动端以固定游戏画布体验为准,入口 `viewport` 需要锁定 `minimum-scale=1.0``maximum-scale=1.0``user-scalable=no`,同时保留 `viewport-fit=cover` 适配安全区。
- 浏览器仍可能通过 iOS `gesture*` 或多指 `touchmove` 触发整页缩放,因此主站启动入口应统一调用 `lockMobileViewportZoom()` 拦截页面级捏合与快速双击缩放。
- 不要在每个画布组件里重复注册缩放拦截;单指滚动、点击、拖拽应继续留给具体页面和玩法处理。