Text & HTML Elements
TEXT elements render text or HTML into a visual layer and compose it into the
video. They have two modes:
- Plain text — set
textand style it with thestyleobject. - HTML — set
htmlwith your own markup. With the optionalcustomCodefield you can attach native CSS and JavaScript, turning aTEXTelement into a fully styled, animated mini web page.
HTML elements support text, badges, layouts, gradients, CSS/WAAPI animation,
and a restricted inline SVG subset for vector shapes.
Existing SVG elements remain supported; their standalone
markup rules differ from the stricter SVG subtree allowed in html.
Interface
interface TextItem {
type: "TEXT";
text?: string;
html?: string;
style?: Record<string, string | number>;
fitToBox?: boolean;
customCode?: CustomCode;
x?: number;
y?: number;
width?: number;
height?: number;
anchor?: Anchor;
position?: PositionPreset;
enterBegin?: number;
enterEnd?: number;
exitBegin?: number;
exitEnd?: number;
track?: number;
opacity?: number;
angle?: number;
flipV?: boolean;
flipH?: boolean;
enterAnimation?: XFadeEffect | null;
exitAnimation?: XFadeEffect | null;
}
interface CustomCode {
css?: string;
js?: string;
animationDuration?: number;
}
Required Fields
| Property | Type | Notes |
|---|---|---|
type | "TEXT" | Case-insensitive in API validation. |
text or html | string | At least one must contain content. |
Placement, timing, layering, and animation fields are shared by all visual elements — see Common Element Properties.
Content
textis plain text. The API rejects<and>in this field.htmlis your own HTML markup and takes priority overtextwhen both are present. The hosted API accepts a safe tag subset:div,span,p,br,b,strong,i,em,u,s,ul,ol,li,img, andcanvas, plus the SVG subset below. HTML elements acceptstyle,class,src,alt,width, andheightattributes.imgsources must be public http(s) URLs or inline rasterdata:image/…URIs.styleaccepts CSS property names and string or number values; it styles the element's root container.customCodeattaches native CSS and JavaScript — see below.
Inline SVG in HTML
html accepts geometry-only SVG: svg, g, defs, gradients/stops, paths,
circles, ellipses, rectangles, lines, polylines, and polygons. Use supported
geometry/paint attributes and local gradient references such as url(#brand).
Scripts, event handlers, foreignObject, use, image, external resources,
and SVG animation tags are rejected. Use HTML text around the SVG for labels,
and customCode CSS/JavaScript for animation.
Text sizing and overflow
Set width and height in pixels when text must fit a defined box. By default,
the renderer preserves the authored typography, so long copy can be clipped.
Set fitToBox: true to shrink typography just enough to keep painted text
inside the declared box. Text that already fits is unchanged; this option
does not enlarge text or replace intentional layout and line breaks.
Fitting reduces type metrics to no less than half their authored size and
does not move fixed layout geometry. Very long copy or fixed negative offsets
can still overflow; inspect representative variable values and the final render.
This element fragment belongs in payload.visuals:
{
"type": "TEXT",
"text": "A product title that may become longer",
"width": 800,
"height": 160,
"position": "center-center",
"fitToBox": true,
"style": { "fontFamily": "Poppins", "fontSize": 64, "color": "#111111" }
}
See Layout for box sizing, anchors, and margins.
Native CSS & JavaScript (customCode)
customCode lets you style, animate, and script the element with the same tools
you use on the web. The element's html is rendered in a headless browser, your
css and js run against it, and the result is captured as the element's visual
layer.
| Field | Type | Notes |
|---|---|---|
css | string | Raw CSS injected into the page. Define @keyframes here and target the classes you used in the element's html. |
js | string | JavaScript run after the content loads. Use it to manipulate the DOM or drive animations with the Web Animations API. |
animationDuration | number | Length of one animation loop in seconds (max 15). Only that loop is captured and then looped to fill the element's timeline. Auto-detected when omitted. |
How animation capture works
When customCode is present, Zvid captures a single loop of your animation
and lets FFmpeg repeat it for the element's on-screen duration. This means the
element's timeline length (enterBegin → exitEnd) does not increase
capture time. Billing still uses the final video's duration and resolution,
so a longer output can cost more credits. Set animationDuration to the exact length of one loop for
a seamless repeat; omit it to let Zvid auto-detect.
Example: CSS keyframe animation
A pulsing badge — no text, just HTML targeted by a CSS class. The following
animation examples are element fragments for payload.visuals. Each recorded
preview includes its own complete project payload:
{
"type": "TEXT",
"html": "<div class=\"badge\">LIMITED OFFER</div>",
"position": "center-center",
"enterBegin": 0,
"exitEnd": 5,
"customCode": {
"css": ".badge { color: #ffffff; font-family: Poppins; font-size: 72px; padding: 20px 40px; background: #e11d48; border-radius: 16px; animation: pulse 1s ease-in-out infinite; } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.18); } }",
"animationDuration": 1
}
}
{
"name": "docs-text-css-pulse",
"width": 960,
"height": 540,
"duration": 5,
"backgroundColor": "#140b2e",
"visuals": [
{
"type": "TEXT",
"html": "<div class=\"badge\">LIMITED OFFER</div>",
"position": "center-center",
"enterBegin": 0,
"exitEnd": 5,
"customCode": {
"css": ".badge { color: #ffffff; font-family: Poppins; font-size: 72px; padding: 20px 40px; background: #e11d48; border-radius: 16px; animation: pulse 1s ease-in-out infinite; } @keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.18); } }",
"animationDuration": 1
}
}
]
}
Example: JavaScript with the Web Animations API
Use js and element.animate(...) when you want to build motion
programmatically:
{
"type": "TEXT",
"html": "<div class=\"price\">$9.99</div>",
"position": "center-center",
"enterBegin": 0,
"exitEnd": 5,
"customCode": {
"css": ".price { color: #fbbf24; font-family: Poppins; font-size: 96px; font-weight: 700; }",
"js": "document.querySelector('.price').animate([{ transform: 'translateY(0)' }, { transform: 'translateY(-30px)' }, { transform: 'translateY(0)' }], { duration: 800, iterations: Infinity, easing: 'ease-in-out' });"
}
}
{
"name": "docs-text-waapi",
"width": 960,
"height": 540,
"duration": 5,
"backgroundColor": "#140b2e",
"visuals": [
{
"type": "TEXT",
"html": "<div class=\"price\">$9.99</div>",
"position": "center-center",
"enterBegin": 0,
"exitEnd": 5,
"customCode": {
"css": ".price { color: #fbbf24; font-family: Poppins; font-size: 96px; font-weight: 700; }",
"js": "document.querySelector('.price').animate([{ transform: 'translateY(0)' }, { transform: 'translateY(-30px)' }, { transform: 'translateY(0)' }], { duration: 800, iterations: Infinity, easing: 'ease-in-out' });"
}
}
]
}
Example: a pure-CSS spinner
Vector-looking graphics don't need markup at all — borders, gradients, and border-radius go a long way:
{
"type": "TEXT",
"html": "<div class=\"ring\"></div>",
"width": 220,
"height": 220,
"position": "center-center",
"enterBegin": 0,
"exitEnd": 5,
"customCode": {
"css": ".ring { width: 160px; height: 160px; border-radius: 50%; border: 14px solid rgba(34,211,238,0.25); border-top-color: #22d3ee; animation: spin 1.5s linear infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }",
"animationDuration": 1.5
}
}
{
"name": "docs-text-css-ring",
"width": 960,
"height": 540,
"duration": 5,
"backgroundColor": "#140b2e",
"visuals": [
{
"type": "TEXT",
"html": "<div class=\"ring\"></div>",
"width": 220,
"height": 220,
"position": "center-center",
"enterBegin": 0,
"exitEnd": 5,
"customCode": {
"css": ".ring { width: 160px; height: 160px; border-radius: 50%; border: 14px solid rgba(34,211,238,0.25); border-top-color: #22d3ee; animation: spin 1.5s linear infinite; } @keyframes spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }",
"animationDuration": 1.5
}
}
]
}
customCode safety
customCode runs inside the rendering browser, so it may only style, script,
and animate the element's own content. The renderer rejects anything that could
reach the network, filesystem, or browser storage, including:
- JavaScript:
fetch,XMLHttpRequest,WebSocket,EventSource,sendBeacon;eval,new Function, string-formsetTimeout/setInterval, dynamicimport()/require;localStorage/sessionStorage/indexedDB,document.cookie; service workers and Web Workers;window.openand navigation (location = ...);document.write. - CSS:
@import,expression(...),-moz-binding,javascript:URLs, andurl(...)pointing at any non-data:resource. Inlineurl(data:...)is allowed.
Keep your animations self-contained — define keyframes, target your own classes, and use the Web Animations API for dynamic motion.
Examples
These are element fragments for payload.visuals, not complete projects.
For video-only timing fields, use a video project with a long enough duration.
Plain Text
{
"type": "TEXT",
"text": "Hello World",
"x": 640,
"y": 360,
"anchor": "center-center",
"style": {
"fontSize": 48,
"color": "#000000",
"textAlign": "center"
}
}
Styled Text With Animation
{
"type": "TEXT",
"text": "Welcome to Zvid",
"position": "center-center",
"enterBegin": 0,
"enterEnd": 1,
"exitBegin": 9,
"exitEnd": 10,
"enterAnimation": "fade",
"exitAnimation": "fade",
"style": {
"fontSize": 36,
"color": "#ff6b35",
"textAlign": "center",
"fontWeight": "bold"
}
}
HTML With Inline Styles
{
"type": "TEXT",
"html": "<div style=\"text-align:center\"><p style=\"color:#ff6b35; margin:0; font-size:48px\">Big Title</p><p style=\"color:#666666; font-size:18px\">Subtitle text</p></div>",
"position": "center-center",
"enterBegin": 0,
"enterEnd": 2,
"exitBegin": 8,
"exitEnd": 10
}
Watermark
{
"type": "TEXT",
"text": "WATERMARK",
"x": 660,
"y": 340,
"anchor": "center-center",
"angle": 45,
"opacity": 0.3,
"track": 10,
"style": {
"fontSize": 72,
"color": "#000000",
"fontFamily": "Anton",
"textAlign": "center"
}
}
Font Handling
Use exact Google Fonts family names, such as Poppins, Montserrat, Roboto,
Open Sans, Lato, Playfair Display, Oswald, or Bebas Neue. Set the
family in style.fontFamily (plain text / HTML) or in your customCode.css.