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 these direct children:

  • <ws-cast> — optional; contains <ws-character> metadata entities
  • <ws-layer> — one or more visual/audio composition layers
  • <ws-shader> — optional; user-defined shader resources referenced by ws-vfx
  • <ws-link> — optional; interactive navigation edges between layers

Layers ​

xml
<ws-layer id="title" z="10" opacity="1">
  ...
</ws-layer>
AttributeTypeDefaultDescription
idstring—Unique layer identifier
labelstringnoneHuman-readable display name; falls back to id in UIs
znumber0Layer z-index (stacking order)
opacitynumber1Layer-level opacity (0–1), multiplied with element opacity
gatestringnoneConditional visibility variable name; evaluated by interactive engines, ignored by standard renderers

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
durnumber∞Duration 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
gatestringnoneConditional visibility variable name; evaluated by interactive engines, ignored by standard renderers

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
durnumber∞Duration 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).


A multi-source media carousel — positioned like ws-image but cycles through multiple media sources with configurable layout modes. Child <ws-source> elements define the media sequence.

xml
<ws-carousel x="0" y="0" width="100%" height="70%" fit="cover"
             layout="dissolve" interval="4000">
  <ws-source src="img1.jpg" />
  <ws-source src="img2.jpg" />
  <ws-source src="vid.mp4" type="video" />
</ws-carousel>
AttributeTypeDefaultDescription
widthunit"100%"Display width
heightunit"100%"Display height
fitenum"cover"Object-fit: cover · contain · fill · none
layoutenum"dissolve"Layout mode: dissolve · before-after · media-wall · pdp-mockup
intervalnumber4000Auto-advance interval in milliseconds
autoplaybooleantrueWhether to auto-advance through sources
AttributeTypeDefaultDescription
srcstringrequiredMedia file URL
typestring"image"Media type: image or video

<ws-note> ​

A semantic annotation element — non-rendered metadata consumed by presentation layers (slideshow labels, export captions, accessibility). Lives inside ws-layer but has no spatial position and is not rendered on canvas. Multiple ws-note elements per layer form the semantic description of that page or slide.

xml
<ws-note role="headline">The Future of Fashion</ws-note>
<ws-note role="cta" href="https://shop.example.com">Shop Now</ws-note>
<ws-note role="caption" target="img-1">Behind the scenes</ws-note>
AttributeTypeRequiredDescription
idstringautoUnique identifier
rolestringyesSemantic role
targetstringnoElement id this note annotates (for element-scoped notes)
hrefstringnoURL (for cta role)

Text content is the note's text node.

Role values ​

headline · tagline · description · caption · cta · stat

Custom role strings are also accepted.


<ws-vfx> ​

A visual effect descriptor nested inside any visual element (ws-text, ws-rect, ws-image, ws-video, ws-carousel). Multiple ws-vfx children form an ordered effect chain. Renderer-optional — renderers that support real-time VFX (e.g. WebGL) apply the chain; others silently ignore it.

Use preset for built-in effects or shader for scene-defined shaders (referencing a <ws-shader> id). Mutually exclusive — at least one must be present.

xml
<ws-image src="photo.jpg" width="100%" height="100%">
  <ws-vfx preset="glitch" intensity="0.6" speed="1.2" />
  <ws-vfx shader="fire-dissolve" intensity="1" />
</ws-image>
AttributeTypeDefaultDescription
presetstringnoneBuilt-in effect preset name (e.g. "glitch", "rgbShift")
shaderstringnoneScene-defined shader id (references <ws-shader>)
intensitynumber1Effect intensity 0–1
speednumber1Animation speed multiplier
enabledbooleantrueWhether the effect is active

Arbitrary shader uniform overrides can be passed as u-* attributes (e.g. u-fireColor="1.0,0.4,0.0").

VFX uniform values can also be animated via <ws-keyframe> using the uniforms property.


<ws-shader> and <ws-uniform> ​

A user-defined shader resource declared at scene root (direct child of <wity-scene>). Renderers resolve ws-vfx shader references against these definitions. Renderers that don't support custom shaders silently fall back or ignore the effect.

xml
<ws-shader id="fire-dissolve" lang="glsl">
  <ws-uniform name="progress" type="float" default="0" min="0" max="1" />
  <ws-uniform name="fireColor" type="vec3" default="1.0,0.4,0.0" />
  <![CDATA[
    // GLSL fragment shader source...
  ]]>
</ws-shader>
AttributeTypeRequiredDescription
idstringyesUnique identifier, referenced by ws-vfx shader attribute
langstringyesShader language: "glsl" or "wgsl"

Shader source code is provided as the element's text content (typically wrapped in CDATA).

<ws-uniform> (inside ws-shader) ​

Declares a uniform variable with type and range metadata for tooling and validation.

AttributeTypeRequiredDescription
namestringyesGLSL uniform name (e.g. "progress")
typestringyesData type: float · int · vec2 · vec3 · vec4
defaultstring/numbernoDefault value (number for float/int, comma-separated for vectors)
minnumbernoMinimum value hint (for UI sliders)
maxnumbernoMaximum value hint (for UI sliders)

Interactive primitives ​

The following elements support interactive/branching scene experiences. They are non-rendered by standard renderers (slideshow, cinema, PDF, video export) and are consumed by the interactive engine (jity-quest).

<ws-hotspot> ​

An interactive hotspot region — a tappable/clickable spatial area within a layer. On user tap, the interactive engine evaluates the configured action.

xml
<ws-hotspot x="10%" y="60%" width="30%" height="15%"
            action="goto" target="layer-5" label="Go to scene 5" />
<ws-hotspot x="50%" y="80%" width="20%" height="10%"
            action="set-var" var="chose_sword" value="true" />
AttributeTypeDefaultDescription
xunit0Horizontal position
yunit0Vertical position
widthunitrequiredHotspot width
heightunitrequiredHotspot height
actionenumrequiredAction type: goto · set-var · animate
targetstringnoneTarget layer id (for goto action)
varstringnoneVariable name to set (for set-var action)
valuestringnoneValue to assign (for set-var action)
labelstringnoneHuman-readable label (for authoring UI)

Hotspots inherit common element attributes (id, begin, dur, gate, etc.).

A scene-level navigation edge — defines a transition in the interactive DAG. Direct child of <wity-scene> (not inside a layer).

xml
<ws-link from="layer-1" to="layer-3" trigger="hotspot-attack" />
<ws-link from="layer-2" to="layer-4" trigger="hotspot-run" condition="has_sword" />
AttributeTypeRequiredDescription
fromstringyesSource layer id
tostringyesDestination layer id
triggerstringnoHotspot id that activates this link; if omitted, link is auto-traversed
conditionstringnoVariable name that must be truthy for this link to be active
labelstringnoHuman-readable edge label (for graph authoring UI)

The gate attribute ​

The gate attribute is available on any visual element (via WsElementBase) and on layers (WsLayer). It specifies a variable name evaluated by the interactive engine to control conditional visibility.

  • When present on a layer: the entire layer (and all its children) is hidden until the named variable becomes truthy.
  • When present on an element: only that element is gated.
  • Standard renderers ignore gate — the element/layer is always visible.
xml
<ws-layer id="reward" z="5" gate="quest_complete">
  <ws-text x="50%" y="50%" anchor="center" font-size="5%" color="#00ff00">
    You found the treasure!
  </ws-text>
</ws-layer>

<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 — interactive product 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-vfx preset="rgbShift" intensity="0.3" />
    </ws-video>
  </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>

  <!-- Product carousel -->
  <ws-layer id="carousel" z="2" label="Product Gallery">
    <ws-carousel x="50%" y="45%" anchor="center"
                 width="80%" height="60%" fit="contain"
                 layout="dissolve" interval="3000"
                 begin="4" dur="8">
      <ws-source src="https://cdn.example.com/product-1.jpg" />
      <ws-source src="https://cdn.example.com/product-2.jpg" />
      <ws-source src="https://cdn.example.com/product-3.jpg" />
    </ws-carousel>
    <ws-note role="headline">New Collection</ws-note>
    <ws-note role="cta" href="https://shop.example.com">Shop Now</ws-note>
  </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>

  <!-- Interactive choice — visible only after intro -->
  <ws-layer id="choice" z="20" gate="intro_done">
    <ws-hotspot x="10%" y="75%" width="35%" height="10%"
                action="goto" target="details" label="View details" />
    <ws-hotspot x="55%" y="75%" width="35%" height="10%"
                action="set-var" var="added_to_cart" value="true"
                label="Add to cart" />
  </ws-layer>

  <!-- Confirmation — gated on cart variable -->
  <ws-layer id="confirmation" z="25" gate="added_to_cart">
    <ws-text x="50%" y="50%" anchor="center"
             font-size="5%" color="#00ff00"
             animate-in="fade" animate-dur="0.4">
      Added to cart!
    </ws-text>
  </ws-layer>

  <!-- Navigation edges (interactive DAG) -->
  <ws-link from="choice" to="details" trigger="hotspot-view" />
  <ws-link from="choice" to="confirmation" trigger="hotspot-cart"
           condition="added_to_cart" />

</wity-scene>