Appearance
Video Playback in Creative-Engine
Components
CreativeVideoBlock.vue
The main video rendering component. Handles both MP4 and HLS playback.
Rendering modes:
streaming: false-- native<video>element with progressive MP4 sourcestreaming: true--@cavai/minimal-videoVideoPlayer component (HLS.js wrapper)
Resolution calculation:
- Adapts video resolution based on device pixel ratio (1x to 1.2x scaling)
- Maximum width capped at 1920px
- Dimensions forced to even pixel values (required for video encoding compatibility)
Layout modes:
scale-- cover with crop (CSSobject-fit: cover)preserve-- contain with letterbox (CSSobject-fit: contain)stretch-- fill (CSSobject-fit: fill)
CreativeVideoControls.vue
Play/Pause and Mute/Unmute toggle buttons overlaid on the video.
- Rendered as a separate
<section class="video-controls">outside Vue templates - Uses
mix-blend-modeand dual layers for a shadow effect - Created/destroyed when the video block mounts/unmounts
Playback Logic
Autoplay
Video autoplays when all conditions are met:
autoplayis enabled in block properties- The creative is in view (intersection observer)
allowAutoStartis true in video state
Pause Conditions
Playback pauses when any of these are reached:
- Loop count:
pauseMeasure: 'loop'withpauseAfter: N-- pauses after N complete loops - Time limit:
pauseMeasure: 'sec'withpauseAfter: N-- pauses after N seconds of total play time - Infinity:
pauseMeasure: 'infinity'-- loops forever (default)
Pause Out of View
When pauseOutOfView is enabled, the video pauses when the creative scrolls out of the viewport and resumes when it comes back into view.
Video Restart (Flow Operator)
The Restart operator in the flow system sets shouldRestart: true in video state. This resets allowAutoStart and restarts playback from the beginning.
Video State
Stored in DataStore.videoState:
typescript
{
state: 'paused' | 'playing' | 'ended',
isMuted: boolean,
allowAutoStart: boolean,
shouldRestart: boolean
}changeVideo (Dynamic Video Swap)
Flow operators and scripts can swap the video at runtime using changeVideo.
How it works:
- A
ChangeVideoOp(or script) sets a newstreamIdon the video block - The
changeVideowatch handler inCreativeBody.vuefires streamParser(streamId)fetches the HLS manifest for the new video- Stream data (including dimensions and HLS segments) is applied to the block
- The video player reloads with the new source
Historical bug (fixed in CE PR #728): Before the fix, changeVideo only passed streamId without streamData, so the engine forced streaming = false and fell back to full MP4 download. The fix fetches the HLS manifest during the swap, enabling streaming for dynamically changed videos.
Metrics
Video playback fires analytics events:
playCount-- tracked on first play onlyplayPercentage-- reported at 0%, 25%, 50%, 75%, 100% thresholds- Sent via
Analytics.sendVideoBackgroundFlow(metrics)
These metrics are separate from VAST tracking events -- they fire for all video playback (not just VAST delivery).