ZWMAP Annotation Type Specification
1. Overview
The annotation protocol follows a mechanism/policy separation principle: 13 node types provide the UI containers, and the unified StandardAction system drives interactions. Use the online annotation editor to create and edit annotation data visually.
Annotation data is a single unified nodes array. (The legacy hotspots + events dual-array format has been abolished; legacy fields are migrated automatically at load time.)
2. ZWMAP Header
{
"zwp_protocol": "ZWMAP/1.0",
"zwp_type": "annotation"
}
Both fields are required.
3. The 13 Node Types
| Group | Types | Notes |
|---|---|---|
| Base elements (4) | hotspot / text / image / button |
Rendered inline on the video; support event.actions |
| Interactive collection (5) | choice / quiz / form / vote / card |
Branch / quiz / form / vote / info card |
| Advanced display (2) | webview / map |
Embedded iframe page / map |
| System flow (2) | countdown / speed_controller |
Countdown (fires an action on expiry) / playback rate |
Common node fields
| Field | Type | Notes |
|---|---|---|
id |
string | Unique across the document (required) |
type |
string | One of the 13 types (required) |
time_range |
array | [start, end] in seconds (required, start < end) |
position |
object | {x, y, w, h} in percent of the video frame; may be omitted for popup types (centered) |
pause_on_show |
bool | Pause playback when entering the range |
mandatory |
bool | Anti-skip protection; popup cannot be dismissed unless dismissible: true is set explicitly |
hidden |
bool | Initially hidden (can be shown via CONTROL_NODE) |
z_index |
number | Stacking order |
animation |
object | {enter, emphasis, exit, duration} |
4. Actions
All interactions are defined via the event.actions[] array; each entry is { "type": ..., "payload": {...} }:
| type | payload | Notes |
|---|---|---|
SEEK_TIME |
target, show_back_btn |
Seek the timeline |
LOAD_ITEM |
target |
Switch playlist item |
PAUSE_MEDIA / PLAY_MEDIA |
— | Force pause / resume |
OPEN_LINK |
url, pause |
Open external link (http/https whitelist) |
CONTROL_NODE |
target_id, operation, auto_hide |
Show/hide/toggle/activate other nodes |
EMIT_MESSAGE |
params, target_origin |
postMessage to the host page |
SUBMIT_DATA |
api_url, method, params |
Submit data to an external API |
SET_VARIABLE |
key, value |
Set a session variable |
5. Full Example
{
"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": "Click for details"
},
{
"id": "quiz_01",
"type": "quiz",
"time_range": [60.0, 90.0],
"pause_on_show": true,
"mandatory": true,
"content": {
"title": "Knowledge check",
"prompt": "Which one is correct?",
"options": [
{ "text": "Option A", "value": "A", "is_correct": false },
{ "text": "Option B", "value": "B", "is_correct": true }
],
"feedback": { "correct": "Correct!", "wrong": "Try again" },
"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. Constraints
- Every
idmust be unique across the document positionvalues are percentages (0-100), not pixelstime_rangemust be an array with the first value smaller than the second- Unknown action/node types are silently ignored (no crash); a single invalid node only skips itself
mandatorypopup nodes are non-dismissible by default (unlesscontent.dismissible: true)