Skip to content

Schema v1.0

Root element

xml
<wity-scene version="1.0" width="1920" height="1080" dur="8.0">
  ...
</wity-scene>
AttributeTypeRequiredDescription
versionstringyesMust be "1.0"
widthnumberyesCanvas width in pixels
heightnumberyesCanvas height in pixels
durnumberyesTotal duration in seconds

Document children

The root <wity-scene> element accepts two types of direct children:

  • <ws-cast> — optional; contains <ws-character> metadata entities
  • <ws-layer> — one or more visual/audio composition layers

Layers

xml
<ws-layer id="title" z="10" opacity="1">
  ...
</ws-layer>
AttributeTypeDefaultDescription
idstringUnique layer identifier
znumber0Layer z-index (stacking order)
opacitynumber1Layer-level opacity (0–1), multiplied with element opacity

Common element attributes

Visual elements (ws-text, ws-rect, ws-image, ws-video) share all of these. ws-audio shares only the temporal subset (id, begin, dur).

AttributeTypeDefaultDescription
idstringautoUnique element identifier
xunit0Horizontal position
yunit0Vertical position
anchorenumtop-leftOrigin point for x/y
beginnumber0Start time in seconds
durnumberDuration in seconds
znumber0Z-index within layer
opacitynumber1Element opacity (0–1)
animate-inenumnoneEntrance animation
animate-outenumnoneExit animation
animate-durnumber0.4Anim duration in seconds
animate-easingstringnoneCustom cubic bezier for animate-in/out: "x1,y1,x2,y2" (same format as CSS cubic-bezier())
namestringnoneOptional human-readable display name

Anchor values

top-left · top · top-right · left · center · right · bottom-left · bottom · bottom-right

Animation values

none · fade · fade-up · fade-down · slide-left · slide-right

Slide animations travel 40px. Default easing: easeOutCubic (entrance) / easeInCubic (exit). Use animate-easing="0.25,0.1,0.25,1" to override with a custom cubic bezier (applied to both directions).

Unit values

FormExampleResolves to
percent"50%"50% of canvas width or height
px"120px"120px
bare120120px

<ws-text>

xml
<ws-text
  x="50%" y="40%" anchor="center"
  font-size="5%" color="#ffffff" font-weight="bold"
  animate-in="fade-up" animate-dur="0.6">
  Opening Night
</ws-text>
AttributeTypeDefault
font-sizeunit"3%"
font-familystring"sans-serif"
font-weightstring"normal"
colorstring"#ffffff"
text-alignenum"center"
line-heightnumber1.4
max-widthunitnone
letter-spacingunit0

Text content is the element's text node.

<ws-keyframe> (inside ws-text, ws-rect, ws-image)

Optional keyframe children animate position or opacity over element-relative time. Multiple <ws-keyframe> elements are sorted by t and interpolated linearly (or with a per-segment easing).

xml
<ws-text x="10%" y="50%" anchor="center"
         font-size="5%" color="#ffffff">
  <ws-keyframe t="0"   x="10%" opacity="0" />
  <ws-keyframe t="1"   x="50%" opacity="1" easing="0.25,0.1,0.25,1" />
  <ws-keyframe t="4"   x="50%" opacity="1" />
  <ws-keyframe t="5"   x="90%" opacity="0" />
  Hello
</ws-text>
AttributeTypeRequiredDescription
tnumberyesElement-relative time in seconds (from element's own begin, not scene time)
xunitnoHorizontal position at this keyframe
yunitnoVertical position at this keyframe
opacitynumbernoOpacity (0–1) at this keyframe
easingstringnoCubic bezier for the segment FROM this keyframe to the next: "x1,y1,x2,y2"
  • Only properties specified in at least one keyframe are animated; others use the element's static attribute value.
  • Keyframe t is element-relative — it does not shift when you move an element on the timeline.
  • Easing is defined on the departing keyframe (CSS convention): the easing on keyframe N controls the curve from N → N+1.
  • <ws-keyframe> and animate-in/animate-out compose independently — animation presets still apply at the element boundaries.
  • Supported on <ws-text>, <ws-rect>, <ws-image>. Not supported on <ws-video> or <ws-audio>.

<ws-rect>

xml
<ws-rect x="0" y="0" width="100%" height="100%" fill="#000000" opacity="0.6" />
AttributeTypeDefault
widthunit"100%"
heightunit"100%"
fillstring"transparent"
strokestringnone
stroke-widthnumber1
rxnumber0

<ws-image>

xml
<ws-image src="https://..." width="100%" height="100%" fit="cover" begin="2" dur="4" />
AttributeTypeDefault
srcstringrequired
widthunit"100%"
heightunit"100%"
fitenum"cover"

fit values: cover · contain · fill · none


<ws-video>

A video clip element — positioned and temporally placed within a layer. Extends all common element attributes.

xml
<ws-video
  src="https://cdn.example.com/clip.mp4"
  width="100%" height="100%" fit="cover"
  begin="0" dur="8"
  volume="0.8" trim-in="2.5">
  <ws-cue begin="1.0" end="3.2" speaker="char1">Welcome back everyone</ws-cue>
</ws-video>
AttributeTypeDefaultDescription
srcstringrequiredVideo file URL
widthunit"100%"Display width
heightunit"100%"Display height
fitenum"cover"Object-fit: cover · contain · fill · none
volumenumber1Playback volume 0–1
trim-innumber0Start offset within the source file (seconds)
trim-outnumbernoneEnd offset within the source file (seconds); omit = play to end
mutedbooleanfalseMute audio track

Both <ws-video> and <ws-audio> may contain optional <ws-cue> children (see below).


<ws-audio>

A temporal audio track element — lives inside a ws-layer but has no visual output and no spatial attributes.

xml
<ws-audio
  src="https://cdn.example.com/music.mp3"
  begin="0" dur="30"
  volume="0.4" loop="false">
  <ws-cue begin="0" end="5.2">Intro melody</ws-cue>
</ws-audio>
AttributeTypeDefaultDescription
idstringautoUnique element identifier
beginnumber0Start time in seconds
durnumberDuration in seconds
srcstringrequiredAudio file URL
volumenumber1Playback volume 0–1
loopbooleanfalseLoop the audio
trim-innumber0Start offset within the source file (seconds)
trim-outnumbernoneEnd offset within the source file (seconds); omit = play to end
namestringnoneOptional human-readable display name

<ws-cue>

Optional timed speech/subtitle cue, nested inside <ws-video> or <ws-audio>. Non-rendered metadata — consumed by analysis services, AI agents, and accessibility tools. Timestamps are relative to the source media file (aligned with trim-in/trim-out), not the scene timeline.

xml
<ws-video src="interview.mp4" begin="0" dur="20" volume="1">
  <ws-cue begin="1.2" end="3.5" speaker="char1">Welcome to the show</ws-cue>
  <ws-cue begin="4.0" end="6.8" speaker="char2">Thanks for having me</ws-cue>
</ws-video>
AttributeTypeRequiredDescription
beginnumberyesStart time within source media (seconds)
endnumberyesEnd time within source media (seconds)
speakerstringnows-character id (links to scene.cast)

Text content is the cue's text node.

In the parsed object, cues are accessed as element.cues: WsCue[] (optional — absent when no cues are present).


<ws-cast> and <ws-character>

The optional <ws-cast> section contains semantic character entities. These are not rendered — they travel with the scene document and are consumed by authoring tools, AI agents, players, and compilers.

xml
<ws-cast>
  <ws-character id="char1" name="Sarah" role="Host"
                description="Energetic, warm presenter"
                avatar-url="https://cdn.example.com/sarah.jpg" />
  <ws-character id="char2" name="Alex" role="Narrator" />
</ws-cast>
AttributeTypeRequiredDescription
idstringyesUnique character identifier
namestringyesDisplay name
rolestringnoRole in the scene (e.g. "Host", "Narrator")
descriptionstringnoFree-form notes or personality description
avatar-urlstringnoURL to avatar or reference image

In the parsed WityScene object, characters are accessed as scene.cast: WsCharacter[].


Full example — product video scene

xml
<?xml version="1.0" encoding="UTF-8"?>
<wity-scene version="1.0" width="1080" height="1920" dur="15.0">

  <!-- Cast metadata (non-rendered) -->
  <ws-cast>
    <ws-character id="char1" name="Maya" role="Host"
                  description="Upbeat product presenter" />
  </ws-cast>

  <!-- Background video -->
  <ws-layer id="video" z="0">
    <ws-video src="https://cdn.example.com/bg-clip.mp4"
              width="100%" height="100%" fit="cover"
              begin="0" dur="15" volume="0" />
  </ws-layer>

  <!-- Music bed -->
  <ws-layer id="audio" z="1">
    <ws-audio src="https://cdn.example.com/music.mp3"
              begin="0" dur="15" volume="0.35" />
  </ws-layer>

  <!-- Poster image — appears mid-scene -->
  <ws-layer id="poster" z="2">
    <ws-image src="https://cdn.example.com/product.jpg"
              x="50%" y="45%" anchor="center"
              width="80%" height="60%" fit="contain"
              begin="4" dur="6"
              animate-in="fade" animate-dur="0.5" />
  </ws-layer>

  <!-- Text overlays -->
  <ws-layer id="graphics" z="10">
    <ws-rect x="0" y="0" width="100%" height="100%"
             fill="#000000" opacity="0.4"
             begin="0" dur="3" animate-out="fade" animate-dur="0.5" />
    <ws-text x="50%" y="38%" anchor="center"
             font-size="7%" font-weight="bold" color="#ffffff"
             animate-in="fade-up" animate-dur="0.6">
      New Collection
    </ws-text>
    <ws-text x="50%" y="52%" anchor="center"
             font-size="3%" color="#cccccc"
             animate-in="fade" begin="0.4" animate-dur="0.5">
      Spring 2026
    </ws-text>
  </ws-layer>

</wity-scene>