Watermark Editor — User Guide
Visually create video watermarks and logo overlays. Supports image and text watermarks, dynamic anti-screen-recording, tile mode, template variables, and ZWMAP JSON export.
Overview
The Watermark Editor is a browser-based WYSIWYG tool for creating video watermark configurations. It outputs JSON conforming to the ZWMAP/1.0 specification, which can be rendered by ZWPlayer during video playback.
Key Features:
- Drag-and-drop image watermark creation
- Text watermarks with template variables and tile mode
- Three behavior modes: Static, Dynamic, and Tile
- Live preview on video canvas
- 50-step undo/redo history
- JSON export / import
- Paste images from clipboard (Ctrl+V)
Quick Start
- Load a video: Paste a video URL in the address bar, or drag and drop a local video file onto the canvas area.
- Add a watermark: Click "+ Image Watermark" or "+ Text Watermark", or drag an image file directly onto the canvas.
- Visual editing: Drag the watermark on the canvas to adjust position. Drag corner handles to resize images. The properties panel updates in real time.
- Configure properties: Adjust opacity, behavior mode, dock direction, font settings, etc. in the detail panel.
- Export: Click "Export JSON" to download the configuration file, or "Copy" to copy the JSON to clipboard.
Layer Types
Image Watermark
Used for brand logos, channel icons, and other static branding elements.
- Add: Click "+ Image" button, drag an image to the canvas, or paste from clipboard (Ctrl+V)
- Image source: Upload a local image (auto-converted to Base64) or enter an image URL directly
- Supported formats: PNG (recommended, supports transparency), JPG, SVG, WebP
- Aspect lock: Enabled by default; maintains ratio when resizing
- Behavior modes: Supports Static and Dynamic (Tile mode not available for images)
Text Watermark
Used for copyright notices, user tracking, dynamic information display, and anti-screen-recording protection.
- Template variables: Use {key} syntax to insert dynamic content (see below)
- Font size range: 10-72px
- Color format: RGBA, semi-transparent white by default
- Auto sizing: Text layer width and height automatically adapt to content
- Behavior modes: Supports Static, Dynamic, and Tile modes
Behavior Modes
Static
The watermark stays fixed at the specified position. Suitable for brand logos and fixed copyright notices.
- Dock direction: Left or Right — determines which edge the X coordinate is measured from. Coordinates auto-convert when switching
- Position coordinates: X/Y as percentage of the player container. The input shows the reference origin (from left / from right / from top)
- Size: Only image watermarks have manual width/height controls; text watermarks auto-size to content
Dynamic
The watermark moves across the screen. A key technique for anti-screen-recording protection.
- Direction: Horizontal, Vertical, Diagonal, or Random
- Speed: 1-10 (controls movement speed)
- Interval: Wait time in seconds before reappearing (0 = no interval)
- Duration: Visible seconds per cycle (0 = always visible)
- Position memory: When reappearing, the watermark continues from where it disappeared
Tile (Text Only)
Text fills the entire screen in a tilted grid pattern, forming a dense anti-screen-recording watermark matrix. Only available for text watermarks.
- Tilt angle: -90° to 90°, default -30° (counterclockwise)
- Row spacing: 50-300px, controls vertical density
- Column spacing: 100-600px, controls horizontal density
Template Variables
Text watermarks support {key} template variables that are resolved dynamically at playback time.
Built-in Variables
| Variable | Description | Update Frequency |
|---|---|---|
{sys_time} | Client local time (YYYY-MM-DD HH:mm:ss) | Every second |
Custom Variables
Any {key} can be used. Values are passed via the variables parameter at playback time.
const player = new ZWPlayer({
url: 'video.mp4',
watermarks: config.watermarks,
variables: {
user_id: '138****1234',
user_name: 'John',
department: 'Engineering',
ip_address: '192.168.1.100'
}
});
Unresolved variables are displayed as-is in the player.
Example
"Confidential | {department} | {user_name} | {sys_time}"
→ "Confidential | Engineering | John | 2026-05-08 14:30:00"
Export Formats
Copy JSON
Copies the ZWMAP JSON to the clipboard. Images are embedded as Base64 data URIs or original URLs.
Export JSON
Downloads a {title}_watermark.json file.
Import JSON
Imports a ZWMAP JSON configuration from a local file, restoring all watermark layers and their properties.
Shortcuts
| Shortcut | Action |
|---|---|
| P | Toggle preview mode |
| Space | Play/pause video |
| Esc | Exit preview / Deselect |
| Delete | Delete selected layer |
| Ctrl+Z | Undo |
| Ctrl+Shift+Z | Redo |
| Ctrl+S | Export JSON |
| Ctrl+V | Paste image from clipboard |
ZWMAP Protocol
The watermark editor outputs JSON conforming to the ZWMAP/1.0 specification:
{
"zwp_protocol": "ZWMAP/1.0",
"zwp_type": "watermark",
"zwp_version": "1.0",
"watermarks": [
{
"id": "wm-1",
"type": "image",
"behavior": "static",
"icon": "logo.png",
"dock": "right",
"x": "5%", "y": "5%",
"width": "15%", "height": "15%",
"opacity": 70
},
{
"id": "wm-2",
"type": "text",
"behavior": "dynamic",
"text": "{user_id} | {sys_time}",
"font_size": 16,
"font_color": "rgba(255,255,255,0.3)",
"opacity": 40,
"movement": {
"direction": "diagonal",
"speed": 2,
"interval": 0,
"duration": 0
}
},
{
"id": "wm-3",
"type": "text",
"behavior": "tile",
"text": "Confidential",
"font_size": 16,
"font_color": "rgba(255,255,255,0.15)",
"opacity": 30,
"tile": {
"angle": -30,
"rowSpacing": 120,
"colSpacing": 300
}
}
]
}
Watermark Format Reference
Input Formats
ZWPlayer supports three ways to pass watermark data:
- URL string — A URL pointing to a ZWMAP JSON file; the player fetches and parses it automatically. — A URL pointing to a ZWMAP JSON file; the player fetches and parses it automatically. — A URL pointing to a ZWMAP JSON file. The player fetches and parses it automatically.
- ZWMAP object — A JSON object with the full protocol header; the player extracts the inner watermarks array. — A JSON object with the full protocol header; the player extracts the inner watermarks array. — A complete JSON object with protocol headers. The player unwraps the inner
watermarksarray. - Watermark array — A plain array of watermark objects, no protocol header required. — A plain array of watermark objects, no protocol header required. — A plain array of watermark objects, passed directly without protocol headers.
// URL string
watermarks: 'https://example.com/watermark.json'
// ZWMAP object
watermarks: { zwp_protocol: 'ZWMAP/1.0', zwp_type: 'watermark', watermarks: [...] }
// Plain array
watermarks: [{ type: 'image', behavior: 'static', icon: 'logo.png', ... }]
Common Fields
| Field | Type | Default | Description |
|---|---|---|---|
type | string | — | Required. "image" or "text" "image" or "text" "image" or "text" |
behavior | string | "static" | "static", "dynamic", or "tile" |
dock | string | "right" | X-axis origin: "left" or "right" |
x | string | "5%" | Horizontal position (px or %) |
y | string | "5%" | Vertical position (px or %) |
opacity | number | 70 | Opacity 0–100 |
hidden | boolean | false | Hide this watermark |
Image Watermark Fields
| Field | Type | Description |
|---|---|---|
icon | string | Required. Image URL or Base64 data URI Image URL or Base64 data URI Image URL or Base64 data URI |
width | string | Width (px or %), default "5%" |
height | string | Height (px, %, or "auto") |
Text Watermark Fields
| Field | Type | Description |
|---|---|---|
text | string | Required. Text content, supports {key} template variables Text content, supports {key} template variables Text content, supports {key} template variables |
font_size | number | Font size (px), default 14 |
font_color | string | Font color (RGBA), default "rgba(255,255,255,0.4)" |
Dynamic Movement Fields
When behavior is "dynamic", add a movement object:
| Field | Type | Default | Description |
|---|---|---|---|
movement.direction | string | "diagonal" | "horizontal", "vertical", "diagonal", or "random" |
movement.speed | number | 2 | Movement speed (1–10) |
movement.interval | number | 0 | Hide wait time (seconds), 0 = always visible |
movement.duration | number | 0 | Visible duration per cycle (seconds), 0 = always visible |
Tile Watermark Fields
When behavior is "tile" (text only), add a tile object:
| Field | Type | Default | Description |
|---|---|---|---|
tile.angle | number | -30 | Tilt angle (degrees), -90 to 90 |
tile.rowSpacing | number | 120 | Row spacing (px) |
tile.colSpacing | number | 300 | Column spacing (px) |
ZWPlayer Integration
Use the exported watermark configuration with ZWPlayer:
// 1. Load JSON configuration
const config = await fetch('watermark.json').then(r => r.json());
// 2. Initialize ZWPlayer with watermark configuration
const player = new ZWPlayer({
playerElm: 'video-container',
url: 'https://example.com/video.mp4',
watermarks: config.watermarks,
variables: {
user_id: '138****1234',
user_name: 'John',
department: 'Engineering'
}
});
Integration notes:
- Watermark positions are based on the player container size, not the video resolution
- Watermark layers use pointer-events: none and do not block player controls
- {sys_time} updates automatically every second
- Custom variables are passed and resolved by ZWPlayer at playback time
- Tile mode watermarks cover the entire video area, suitable for anti-screen-recording scenarios