VideoAnnotator
Review footage with timed annotations, a persistent filmstrip, clickable timeline ranges and frame exports.
Live TypeScript example
Try the component here, then use the source below in your application.
- JavaScript
- 13.4 KiB
- Component CSS
- 3.9 KiB
- Shared theme CSS
- 5.5 KiBonce per application
How sizes are measured
The JavaScript figure includes this component’s required helpers. CSS includes its styling dependencies. Each entry is bundled separately for ES2022, minified, then compressed with gzip level 9. Your bundler may share helpers across components. Images, fonts, examples and application code are excluded.
Before compression: JavaScript 37.0 KiB; component CSS 18.2 KiB. These figures describe browser assets, not the complete package download.
View all component measurements →Interact with the example to explore its inputs and callbacks.
import '@blukavantui/community/theme.css'
import {createVideoAnnotator} from '@blukavantui/pro/video-annotator';
import type {BluVideoAnnotation} from '@blukavantui/pro/video-annotator';
import '@blukavantui/community/theme.css';
import '@blukavantui/pro/video-annotator.css';
export function mount(host:HTMLElement) {
// Supply your own licensed, same-origin video and optional WebVTT captions.
const target=document.createElement('div'),reload=document.createElement('button');
reload.textContent='Reload saved review';reload.type='button';host.append(reload,target);
const storageKey='my-app:video-review';let revision=0;
let saved:BluVideoAnnotation[]=JSON.parse(localStorage.getItem(storageKey)||'[]');
const component=createVideoAnnotator(target,{
SourceUrl:'/media/review.mp4',PosterUrl:'/media/review.jpg',Title:'Creative review',
Annotations:saved,Resources:[{Key:'maya',Name:'Maya Chen',Position:'Creative lead',Color:'Purple'}],CurrentUserKey:'maya',ShowPopups:true,
},{
SaveRequested:(requestId,annotations)=>{
try {
// Replace localStorage with an authenticated API and await its successful response.
localStorage.setItem(storageKey,JSON.stringify(annotations));saved=structuredClone(annotations);
queueMicrotask(()=>component.update({SaveResultRequestId:requestId,SaveResultSuccess:true,SaveResultMessage:'Review saved.'}));
} catch {queueMicrotask(()=>component.update({SaveResultRequestId:requestId,SaveResultSuccess:false,SaveResultMessage:'Could not save. Your changes remain.'}));}
},
Exported:(_dataUrl,seconds)=>{reload.textContent='Reload saved review · exported '+seconds.toFixed(2)+'s';},
});
reload.onclick=()=>component.update({Annotations:structuredClone(saved),ResetKey:String(++revision)});
return {destroy(){component.destroy();reload.remove();target.remove();}};
}
const instance = mount(document.getElementById('example')!)
// When this page or framework component is removed:
// instance.destroy()
Install the library and add the host element
npm install https://blukavantui.blutekmedia.com/downloads/blukavantui-community-0.4.0.tgz
# Install your licensed Pro archive alongside Community
npm install ./blukavantui-pro-0.2.1.tgz<div id="example"></div>Community components use @blukavantui/community. The ten Pro components use the separate @blukavantui/pro add-on alongside Community. Your application handles persistence and authentication through its typed callbacks. Choose the matching edition when installing the example.
createVideoAnnotator
Use createVideoAnnotator with the selective CSS. Supply SourceUrl, timed Annotations and Resources. Pause and choose a drawing tool, or use Add annotation and position/time fields without dragging. The persistent timeline seeks to a comment when selected. SaveRequested returns the whole annotation list; persist it separately from the video and acknowledge SaveResultRequestId only after success. Reload with Annotations plus a new ResetKey. The source file is never modified. Captions and audio descriptions belong to your media. Use same-origin or CORS-enabled footage for frame/PNG export.
import { createVideoAnnotator } from '@blukavantui/pro/video-annotator';
import '@blukavantui/pro/video-annotator.css';Load @blukavantui/community/theme.css once in your app shell.createVideoAnnotator(host: HTMLElement, options: VideoAnnotatorOptions, events?: VideoAnnotatorEvents)Reference for @blukavantui/pro 0.2.1. Required and optional follow the shipped TypeScript declarations; optional does not imply a particular default. Pass typed arrays and objects directly where shown.
Options
18| Name | Type / requirement | Usage |
|---|---|---|
SourceUrl | stringRequired | Video file URL. PNG export and filmstrip sampling need same-origin media or an origin that allows CORS. |
PosterUrl | stringOptional | Optional image displayed before playback. |
Title | stringOptional | The displayed title. |
CaptionsUrl | stringOptional | WebVTT captions URL; provide accessible media alternatives appropriate for your footage. |
CaptionLanguage | stringOptional | |
CaptionLabel | stringOptional | |
Annotations | BluVideoAnnotation[]Required | Timed annotations with stable Key, StartTime and EndTime in seconds. Kind supports Box, Arrow, Pin and Freehand. |
Resources | BluResource[]Optional | Reviewers with Key, Name, ImageUrl, Color and Position. |
CurrentUserKey | stringOptional | Resource key assigned to newly created annotations. This is display metadata, not authorization. |
IsReadOnly | booleanOptional | Displays the current value without allowing edits. |
ShowPopups | booleanOptional | Show annotation comments while playback is inside their time window. |
ExportFileName | stringOptional | |
ResetKey | stringOptional | |
SaveResultRequestId | stringOptional | |
SaveResultSuccess | booleanOptional | |
SaveResultMessage | stringOptional | |
AccessibleLabel | stringOptional | Accessible name for assistive technology. |
ExtendedClass | stringOptional | Additional CSS class names on the component root. |
Callbacks
6| Name | Type / requirement | Usage |
|---|---|---|
AnnotationsChanged | (annotations: BluVideoAnnotation[]) => void | Promise<void>Optional | |
SelectionChanged | (key: string) => void | Promise<void>Optional | Reports the new selection to your application. |
PlaybackChanged | (seconds: number, state: "Paused" | "Playing") => void | Promise<void>Optional | Reports current seconds and Playing/Paused state. |
SaveRequested | (requestId: string, annotations: BluVideoAnnotation[]) => void | Promise<void>Optional | Persist the complete timed annotation list, then acknowledge the same request ID. |
Exported | (dataUrl: string, seconds: number) => void | Promise<void>Optional | Reports the PNG data URL and exported frame time in seconds. |
Error | (message: string) => void | Promise<void>Optional |
Instance methods & properties
3| Name | Signature / type | Usage |
|---|---|---|
element | HTMLElement | Root owned by this instance. Dispose before removing its host. |
update | (patch: Partial<VideoAnnotatorOptions>) => void | Apply a partial options update to this instance. |
destroy | () => void | Dispose the instance and its listeners when the view is removed. |
Related data types
Expand a type for its fields and allowed values.
BluImageAnnotation
interface BluImageAnnotation {
AuthorKey?: string;
AuthorName?: string;
AuthorImageUrl?: string;
/** Unique annotation key. */
Key: string;
/** Box, Arrow, Pin or Freehand. */
Kind: "Box" | "Arrow" | "Pin" | "Freehand";
/** Normalized horizontal start coordinate, from 0 to 1. */
X?: number;
/** Normalized vertical start coordinate, from 0 to 1. */
Y?: number;
/** Normalized horizontal extent; arrows may use a negative extent. */
Width?: number;
/** Normalized vertical extent; arrows may use a negative extent. */
Height?: number;
/** Freehand points as an array of {X,Y}, normalized from 0 to 1. */
PointsJson?: string;
/** Annotation comment, also available in the accessible list. */
Text?: string;
/** Shared ComponentColor code. */
Color?: ComponentColor;
}BluResource
interface BluResource {
/** Stable application-owned person/resource key. */
Key: string;
Name: string;
ImageUrl?: string;
Color?: ComponentColor;
/** Role, title or position displayed next to the person. */
Position?: string;
}BluVideoAnnotation
Timestamped review marks. Times are seconds; intervals include start and exclude end.
interface BluVideoAnnotation extends BluImageAnnotation {
StartTime: number;
EndTime: number;
}Use these inputs, events, actions and structures in Service Studio. Names and data bindings are specific to the native Blocks.
One of ten Pro components on Web and OutSystems. Commercial license required. View OutSystems editions →
Open OutSystems showcase ↗Tab reaches playback, timeline, tools and review cards. Use the seek slider with arrow keys, or activate a timeline annotation to seek directly. Add annotation and numeric position/time controls provide alternatives to dragging. Supply captions and audio descriptions for your media; the new component is pending full WCAG 2.2 review.
The compiled component output is under review against applicable WCAG 2.2 A/AA requirements.
Accessibility support →Purpose and use
Pause a shot, draw boxes, arrows, pins or freehand marks, add reviewer comments and save a timed review. Play back notes in context or export the current frame.
Keyboard design guidance
Tab reaches playback, timeline, tools and review cards. Use the seek slider with arrow keys, or activate a timeline annotation to seek directly. Add annotation and numeric position/time controls provide alternatives to dragging. Supply captions and audio descriptions for your media; the new component is pending full WCAG 2.2 review.
See the support status above for review coverage and any limitations.
In your application
Provide useful labels, preserve visible focus, and test the component with your actual content. Use text alongside status colors and check contrast in each state.
Events0No events yet.
Interact with an example to see its events.