Permalink to SVS StylesheetsSVS Stylesheets

SVS (.svs) files define reusable, typed configuration values using a CSS-like syntax. They configure Film appearance, caption appearance, Media presentation and motion, text styling, generation settings, and typography choices. SVS values are called Recipes — they are immutable typed Records that consuming components validate and interpret.

Permalink to basic-syntaxBasic syntax

svs
<?svml using="@hypit/svs@1"?>

<sheet version="1" id="studio">
  film.vertical {
    background: #09090B;
  }

  /* Comments use CSS-style block syntax. */
  caption.primary {
    fill: #FFFFFF;
    size: 58;
  }
</sheet>
  • The processing instruction <?svml using="@hypit/svs@1"?> selects the SVS parser.
  • The <sheet> element wraps all declarations. The id attribute becomes the top-level namespace.
  • Each block is namespace.name { ... } with ;-terminated key-value properties.
  • Comments use /* ... */.

Permalink to importing-and-referencingImporting and referencing

Import an SVS file in your .svml source with a namespace prefix:

svml
<import as="recipes" source="./recipes.svs"/>

Then reference individual Recipes via {recipes.film.vertical}, {recipes.caption.primary}, etc. The prefix comes from the as= attribute; the path comes from namespace.name in the sheet.

Permalink to filmFilm

Film appearance owns only the canvas clear color. Canvas dimensions are an explicit space:Canvas graph value, while frame rate comes from ProgramSpace.

svs
film.vertical {
  background: #09090B;
}
PropertyDescription
backgroundCanvas clear color (hex)

Referenced by film:Film via the appearance attribute:

svml
<space:Canvas id="vertical" width="1080" height="1920"/>
<film:Film id="main" canvas={vertical} semantic={speech.semantic} appearance={recipes.film.vertical}>

Permalink to caption-fineCaption Fine

The first official Caption Style family keeps planning and rendering parameters in one Recipe.

svs
caption.dialogue {
  stack-order: 70;
  x: 0.08;
  y: 0.76;
  width: 0.84;
  size: 58;
  line-height: 0.96;
  align: center;
  fill: #FFFFFF;
  background: #09090BCC;
  padding: 16 24;
  radius: 18;
}
PropertyDescription
stack-orderZ-stacking order among all Tracks (higher = on top)
x, yPosition as fraction of canvas (0–1)
widthWidth as fraction of canvas
sizeFont size in pixels
line-heightLine height multiplier
alignText alignment: left, center, right
fillText color (hex, supports alpha)
backgroundContainer background color (hex, supports alpha like #09090BCC)
paddingContainer padding in pixels (single value or vertical horizontal)
radiusContainer border radius in pixels

For reproducible rendering, select an exact installed face in the .svml source and pass that Record to the Fine Style. Family, weight and style have one source of truth on this exact font edge:

svml
<fonts:Stack id="caption-font" family="inter" weight="600" style="normal"/>
<caption-fine:Style id="primary-caption" recipe={recipes.caption.dialogue}
  font={caption-font}/>

Permalink to per-role-caption-stylesPer-role caption styles

Define multiple caption Recipes for different speakers:

svs
caption.alice {
  stack-order: 70;
  x: 0.08; y: 0.76; width: 0.84;
  size: 58;
  line-height: 0.96;
  align: center;
  fill: #73FBD3;
  background: #09090BCC;
  padding: 16 24; radius: 18;
}

caption.bob {
  stack-order: 70;
  x: 0.08; y: 0.76; width: 0.84;
  size: 58;
  line-height: 0.96;
  align: center;
  fill: #FFD166;
  background: #09090BCC;
  padding: 16 24; radius: 18;
}

Then assign them via caption:Program:

svml
<fonts:Stack id="caption-font" family="inter" weight="600" style="normal"/>
<caption-fine:Style id="default-caption" recipe={recipes.caption.dialogue} font={caption-font}/>
<caption-fine:Style id="alice-caption" recipe={recipes.caption.alice} font={caption-font}/>
<caption-fine:Style id="bob-caption" recipe={recipes.caption.bob} font={caption-font}/>
<caption:Program id="caption-program" document={story.caption} default={default-caption}>
  <caption:Use role="ALICE" style={alice-caption}/>
  <caption:Use role="BOB" style={bob-caption}/>
</caption:Program>

Permalink to media-trackMedia Track

Media keeps spatial placement, frame presentation and lifecycle motion separate. A SpatialFrame owns position and size; the appearance Recipe owns fitting and the frame material; an optional motion Recipe owns enter, sustain and exit behavior.

svs
media.product {
  stack-order: 40;
  fit: contain;
  playback: hold-start;
  frame-paint: #111116;
  clip: rounded;
  radius: 28;
  padding: "0";
  border-width: 1;
  border-style: solid;
  border-color: #FFFFFF20;
  shadows: 0 10 24 0 #00000066;
}

motion.product {
  enter: slide;
  enter-frames: 8;
  enter-direction: up;
  enter-easing: ease-out;
  exit: fade;
  exit-frames: 6;
  exit-easing: ease-in;
}
PropertyDescription
stack-orderZ-stacking order
fitcontain, cover, fit-width, fit-height, native, scale-down, or stretch
frame-x, frame-yAlignment point inside the placement Frame
content-x, content-yIndependently selected focal point inside the source
playbackTimed-source occupancy such as once-start, hold-start, loop-end, or stretch
frame-paintSolid or gradient Paint behind the sampled source
clip, radius, paddingFrame clipping and inset
border-*, shadowsFrame-owned border and ordered shadows
enter, exitLifecycle operator; its frame count, easing and direction use separate properties
sustainZero or more deterministic local motions such as float 12 2 up

Position remains an explicit graph edge:

svml
<space:Frame id="product-frame" within={vertical}
  left="8%" top="20%" right="92%" bottom="68%"/>
<media-track:Item media={product-media.media}
  during={story.selection.demo} frame={product-frame}
  appearance={recipes.media.product} motion={recipes.motion.product}/>

Permalink to textText

Text overlay appearance — typography and Paint. Placement is a separate SpatialFrame graph edge.

svs
text.title {
  stack-order: 90;
  weight: 900;
  size: 64;
  align: center;
  fill: #FFFFFF;
  tracking: -1;
}
PropertyDescription
stack-orderZ-stacking order
weightFont weight
sizeFont size in pixels
alignText alignment
fillText color
trackingLetter spacing adjustment

Compiled with exact font bytes into a text:Style, then referenced by a concrete placement form:

svml
<fonts:Stack id="title-font" family="inter" weight="900" style="normal"/>
<text:Style id="title-style" recipe={recipes.text.title} font={title-font}/>
<text:Area id="meaning" placement={title-frame} style={title-style} during="program">
  MEANING
</text:Area>

Permalink to speaker-text-templateSpeaker Text Template

The Recipe selects the prompt axes declared by the data-only speaker-v1 Text Template. Model, resolution, references and duration remain explicit inputs to seedance:ReferenceVideo; they are not hidden in this Recipe.

svs
speaker.host {
  composition-stability: soft-locked;
  camera-motion: none;
  edit-rhythm: continuous-take;
  performance: natural-explainer;
  gesture: natural;
}
PropertyDescription
composition-stabilityCamera/composition consistency: flexible-ugc, soft-locked, strict-locked
camera-motionCamera movement: none, subtle-punch-in-return
edit-rhythmEditing style: continuous-take, pause-trim-jump-cuts
performanceActing style: natural-explainer, high-energy-ugc, calm-authority, reactive-playful
gestureGesture intensity: restrained, compact, natural, expressive
Referenced by text:Render together with the Kit's Template:
svml
<text:Render id="hook-prompt"
  template={speaker-kit.speaker-v1} recipe={recipes.speaker.host}>
  <text:Set name="dialogue" text={story.segment.hook.dialogue}/>
  <text:Set name="action" text={hook-action}/>
</text:Render>

Permalink to generic-text-template-recipesGeneric Text Template Recipes

The same precedence is available without a domain wrapper. text:Render can read any SVS Recipe, project only properties declared by its template, and let explicit text:Param children override them. This is how the data-only Seedance B-roll, Podcast, Call, Street Interview and reference transfer Kits remain separate from Seedance execution.

svs
broll.product-demo {
  material-mode: product-beauty;
  story-shape: process-demo;
  edit-language: insert-cutaway;
  camera-language: product-macro;
  motion-intensity: readable;
}

Street Interview, Podcast and Call use the same Recipe mechanism rather than hand-written fixed prompt prose. For example:

svs
interview.street {
  framing: soft-handheld;
  pacing: compact;
  performance: natural-street;
  reaction: active;
  gesture: natural;
}

street-interview-v1 reads those five axes. Its per-take action carries camera changes in authored order. podcast-v1 and call-v1 read the corresponding framing, edit-language, pacing, performance, reaction and gesture axes with their own finite values. The selected Kit file is the authority for allowed values and defaults.

Model, resolution, duration and reference media are not template policy. They stay on the exact model Surface and graph edges.

Permalink to exact-font-declarationsExact font declarations

SVS describes typography policy, but it does not choose or open font bytes. For common open fonts, import the private pre-release catalog and select only the faces the Author Graph uses:

svml
<import as="fonts" from="@hypit/fonts-open@1"/>

<fonts:Stack id="caption-fonts" family="inter" weight="600" style="normal" emoji="color">
  <fonts:Fallback family="noto-sans-sc" weight="600" style="normal"/>
</fonts:Stack>
PropertyDescription
familyA family from the package's finite catalog
weightExact selected face weight
styleSelected style: normal or a family-supported italic
emojiOptional color (COLRv1) or mono fallback on Stack

The catalog contains 109 open families across handwriting, script, display, sans, serif, monospace, CJK, world-script and Emoji categories. Fontsource dependencies are pinned to 5.3.0; the Chromium-compatible COLRv1 Emoji package is pinned separately. The compiler hashes installed bytes into Resource-backed font values. It performs no download during a build, and the Runtime never guesses a font:

svml
<caption-fine:Style id="dialogue" recipe={recipes.caption.dialogue}
  font={caption-fonts}/>

fonts:Stack emits one generic FontStackRef; its primary and fallbacks preserve their own honest metadata. The Caption Recipe does not repeat family, weight or style. CJK and Emoji can be split into several Unicode-range files while remaining one logical graph edge. Terminal Text and Fine Caption reject an omitted stack; machine-font fallback is not part of Visual IR. For a symbol with both text and Emoji presentation, write the authored Unicode Emoji sequence (for example ☎️, including VS16); no package rewrites display text to force color.

Brand and custom fonts remain explicit author assets rather than additions to the shared catalog:

svml
<import as="media" from="@hypit/media@1"/>
<media:Font id="brand" src="./assets/Brand-Semibold.woff2"
  weight="600" style="normal"/>

Permalink to combination-exampleCombination example

A complete recipes.svs file for a four-take talking-head project:

svs
<?svml using="@hypit/svs@1"?>

<sheet version="1" id="studio">

  speaker.host {
    composition-stability: soft-locked;
    camera-motion: none;
    edit-rhythm: continuous-take;
    performance: natural-explainer;
    gesture: natural;
  }

  film.vertical {
    background: #09090B;
  }

  caption.primary {
    stack-order: 70;
    x: 0.08;
    y: 0.74;
    width: 0.84;
    size: 44;
    line-height: 1;
    align: center;
    fill: #FFFFFF;
    background: #09090BCC;
    padding: 14 20;
    radius: 16;
  }
</sheet>

This file is imported once in the .svml source and its values are referenced throughout:

svml
<import as="recipes" source="./recipes.svs"/>

<text:Render id="hook-prompt" template={speaker-kit.speaker-v1}
  recipe={recipes.speaker.host}>...</text:Render>

<caption-fine:Style id="primary-caption" recipe={recipes.caption.primary} font={caption-font}/>

<space:Canvas id="vertical" width="720" height="1280"/>
<film:Film id="main" canvas={vertical} semantic={speech.semantic} appearance={recipes.film.vertical}>