Files
huajishe-tts/docs/dev-log/02-ui-primitives-api-design.md
Claude 24822d0d6a docs(dev-log): add chronological development log
Per user request: split the development process into per-topic docs under
docs/dev-log/. Each entry follows the same structure:
  What was asked → Problems → How solved

Files:
- README.md            index
- 01-initial-scope-and-design.md
- 02-ui-primitives-api-design.md
- 03-monorepo-scaffold.md
- 04-ui-primitive-impl.md
- 05-drag-and-drop.md
- 06-three-games.md
- 07-bugfixes-round-1.md
- lessons-learned.md   all gotchas consolidated
- decisions.md         locked decisions with dates

Total: 1071 lines across 10 files.
2026-08-17 16:49:09 +08:00

2.7 KiB
Raw Permalink Blame History

02 · UI 原语 API 设计

做什么

在动手写代码之前,先把 UI 组件的 props、game.ui 字段结构、数据流定义清楚,写成 docs/ui-primitives.md 供实现参考。

遇到什么问题

  1. 接口界定:组件要通用(支持任意 boardgame.io 游戏),又不能过于抽象失去表现力。
  2. game.ui 字段怎么设计:是松散的"约定"还是强类型的 schema
  3. 拖拽 APITTS 用 Lua 控制每个对象的交互。JS 端怎么抽象?
  4. 玩家视角boardgame.io master 会按 playerID 过滤状态UI 怎么配合?

怎么解决

5 个设计原则

  1. 声明式:业务代码只描述"是什么",不描述"怎么画"
  2. 数据驱动:所有可见状态都来自 Gboardgame.io 的 state
  3. 服务器权威:所有 game-affecting 操作都通过 onMove 触发 reducer
  4. 玩家视角UI 接收的 G 已经是 boardgame.io 过滤后的版本
  5. 可扩展:通过 game.ui.overrides 注入自定义组件

8 个组件

<Board> <Zone> <Hand> <Deck> <Card> <Token> <ActionButton> <Dice>

6 个 zone type

hand / pile / discard / grid / area / free

关键 schema

interface UISchema {
  background?: string;
  zones: ZoneDef[];
  cards?: CardTemplate;
  tokens?: TokenDef[];
  actions?: ActionDef[];
  overrides?: UIOverrides;
}

interface ZoneDef {
  id: string;
  type: 'hand' | 'pile' | 'discard' | 'grid' | 'area' | 'free';
  position: { x: number; y: number };
  size?: { w: number; h: number };
  layout?: { fan?: number; spacing?: number; maxWidth?: number };
  faceDown?: boolean;
  owner?: string | null;       // 'self' | 'P0' | null(公开)
  collection?: string;         // G 中持有 ID 数组的字段名
  entityField?: string;        // G 中持有 ID → 实体映射的字段名
  dropMove?: string;           // 接收 drop 时调用的 move
  dropArgs?: (cardIds, fromZoneId, toZoneId) => any[];
  accepts?: string | ((card, ctx) => boolean);  // 接收规则
}

6 个待决项(已锁定

待决项 决定
zone 坐标系统 固定像素 + Board 视口缩放
动画策略 CSS transition 默认 + 游戏可覆盖
可访问性 v1 仅鼠标
触屏/移动端 v1 仅桌面
多选 UI v1 仅 Shift+click
牌堆数量显示 角标显示数量

资产格式SVG 内嵌字符串优先fallback DataURL/URL

成果

  • docs/ui-primitives.md15 KB511 行)
  • 6 个待决项的设计默认值锁定,避免实现时反复讨论

关联