ZWMAP 标注类型规范

1. 概述

标注协议遵循机制与策略分离原则:13 种节点类型提供底层 UI 容器,统一动作体系(StandardAction)负责交互行为,业务场景由用户自由组合。使用 在线标注编辑工具 可以可视化创建和编辑交互标注数据。

标注数据是一个统一的 nodes 数组(旧版 hotspots + events 双数组格式已废除,加载时自动迁移旧字段)。

2. ZWMAP 头部

{
  "zwp_protocol": "ZWMAP/1.0",
  "zwp_type": "annotation"
}

zwp_protocol 和 zwp_type 为必填字段。

3. 13 种节点类型

分组 类型 说明
基础元素 (4) hotspot / text / image / button 内联渲染在视频画面上,支持 event.actions 交互
交互收集 (5) choice / quiz / form / vote / card 选项分支 / 测验 / 表单 / 投票 / 信息卡片
高级展示 (2) webview / map 网页 iframe 嵌入 / 地图
系统流程 (2) countdown / speed_controller 倒计时(到期触发动作)/ 播放变速控制

节点公共字段

字段 类型 说明
id string 全文档唯一(必填)
type string 13 种类型之一(必填)
time_range array [start, end] 秒(必填,start < end)
position object {x, y, w, h} 画面百分比 0-100;弹窗类节点可省略(居中显示)
pause_on_show bool 进入区间时暂停播放
mandatory bool 强制节点:跳过会被拉回;未显式设置 dismissible 时弹窗不可关闭
hidden bool 初始隐藏(可由 CONTROL_NODE 动态显示)
z_index number 层叠顺序
animation object {enter, emphasis, exit, duration} 动画

4. 动作类型 (Actions)

所有交互通过 event.actions[] 数组定义,每项为 { "type": ..., "payload": {...} }:

type payload 参数 说明
SEEK_TIME target, show_back_btn 时间轴跳转
LOAD_ITEM target 切换播放列表项
PAUSE_MEDIA / PLAY_MEDIA — 强制暂停 / 恢复播放
OPEN_LINK url, pause 打开外部链接(http/https 白名单)
CONTROL_NODE target_id, operation, auto_hide 控制其他节点显隐(show/hide/toggle/activate)
EMIT_MESSAGE params, target_origin 向宿主页面 postMessage
SUBMIT_DATA api_url, method, params 向外部 API 提交数据
SET_VARIABLE key, value 设置会话变量

5. 完整示例

{
  "zwp_protocol": "ZWMAP/1.0",
  "zwp_type": "annotation",
  "zwp_version": "1.0",
  "nodes": [
    {
      "id": "hs_link_01",
      "type": "hotspot",
      "time_range": [3.0, 15.0],
      "position": { "x": 10, "y": 20, "w": 25, "h": 15 },
      "event": {
        "trigger": "click",
        "actions": [
          { "type": "OPEN_LINK", "payload": { "url": "https://www.example.com", "pause": true } }
        ]
      },
      "style": { "border_color": "#FF6B6B", "border_width": 1 },
      "animation": { "enter": "fadein", "emphasis": "pulse", "exit": "none", "duration": 500 },
      "hint": "点击查看详情"
    },
    {
      "id": "quiz_01",
      "type": "quiz",
      "time_range": [60.0, 90.0],
      "pause_on_show": true,
      "mandatory": true,
      "content": {
        "title": "知识检查",
        "prompt": "以下哪个是正确的?",
        "options": [
          { "text": "选项 A", "value": "A", "is_correct": false },
          { "text": "选项 B", "value": "B", "is_correct": true }
        ],
        "feedback": { "correct": "回答正确!", "wrong": "请重试" },
        "max_attempts": 2,
        "fallback_time": 60.0,
        "show_toast": true
      }
    },
    {
      "id": "cd_01",
      "type": "countdown",
      "time_range": [55.0, 62.0],
      "position": { "x": 40, "y": 35, "w": 20, "h": 30 },
      "content": {
        "countdown": 5,
        "pause_during": true,
        "on_expire": { "type": "PLAY_MEDIA", "payload": {} }
      }
    }
  ]
}

6. 约束规则

  1. 每个 id 在整个文档范围内必须唯一
  2. position 的值为百分比(0-100),非像素值
  3. time_range 必须是数组且第一个值小于第二个值
  4. 未知 Action / 节点 type 静默忽略,不导致播放器崩溃;单条非法节点只跳过自身
  5. mandatory 弹窗类节点默认不可关闭(除非 content.dismissible: true 显式允许)