Skip to content

ASSv5 Override Tags

Ryan Lucia edited this page Feb 17, 2019 · 5 revisions

ASSv5 Override Tag Specification Proposal

TODO:

  • Document implementation details for specific tags (e.g. blur).
  • Add images corresponding to the various examples.
  • Document remaining tags
    • Drawing syntax (svg)
    • Fill (gradients with multiple stops and bitmaps)
  • Figure out \scale
  • Corner pinning?
  • Ruby text
  • Clip mask type
  • Decide layering
  • Paths/keyframing/animation?
  • Adjust comments?
  • Handle parser error behavior (in both docs)

Key Differences from old ASS Override Tags:

Tag Consolidation

ASSv5 favors a small set of tags that can take differing sets of arguments. This is something old ASS is very inconsistent about.

For example, old ASS has the tags \bord, \xbord, and \ybord for manipulating the appearance of a subtitle line's outline. The ASSv5 equivalent has the same name but with two forms: \bord(4) and \bord(4,3). The second form specifies the x and y borders separately, while the first specifies them to be the same value.

This style of tag has some precedence in ASS. The primary example being \t which has 4 forms:

\t([start],[end],[accel],[tags])
\t([start],[end],[tags])
\t([accel],[tags])
\t([tags])

There are other tags that exhibit these properties, including (but not necessarily limited to) \clip, \iclip, \move, and \b.

Viewport-based Units

In old ASS, scripts have an absolute resolution and units are specified in pixels. This has been modified for ASSv5. Now, scripts define a virtual canvas size which is stretched across the viewport when rendered.

All tags, both positional and size-based, use these units rather than pixel-based ones, without exception.

Override Tag Syntax Overview

Override tags are wrapped inside {}, referred to as a tag block from now on. Within a tag block, all text that is not part of an override tag is ignored by the renderer.

In general, an ASSv5 override tag will be of the form \tagname(arguments...), where arguments... is a comma (ASCII 0x2C) delimited list of arguments that defines the tag's behavior.

There is one exception to this syntax rule: tags that take a single numeric or boolean argument may optionally have the parentheses omitted.

Arguments that take multiple values can omit certain arguments by leaving 0 or more spaces (ASCII 0x20) in place of an argument. Commas may not be omitted. Not all override tags accept omitted arguments. Omitted arguments will be interpreted as the currently existing value.

Examples:

\bord(2,3) sets the x border to 2 and the y border to 3.

\bord(3,) sets the x border to 3 but leaves the y border as the default value.

\bord(,1.5) sets the y border to 1.5 but leaves the x border as the default value.

Argument Types

There are a number of different argument types available in ASSv5.

Boolean

Boolean arguments may be either + (true) or - (false).

Example:

{\b(+)}This text is bold. {\b(-)}This text is not.

Integer

Integers are expressed as base 10. Leading zeroes are ignored.

Example:

\an(1)

Floating Point

Floating point values are expressed as base 10, and may use E-notation.

Example:

\bord(1.5,5.8.9e-4)

Percent

Percent values are expressed the same way as floating point numbers, but do not accept E-notation. They are suffixed by a % character. Negative percents are allowed.

Percent tags behave similarly to the way they do in CSS: they modify the inherited value of the attribute and modify that, rather than setting a specific value. This applied regardless of the override blocking. Unless specifically noted otherwise, all tags that take percent values as arguments exhibit this behavior. Because percentage modification is multiplicative, values of 0 will always be 0 no matter what percent they are modified by.

Example:

{\bord(5)}border of 5{\bord(2)\bord(40%)}border of 0.8

As shown in the above example, the \bord(40%) overrides the \bord(1) contained in the same override block because the last tag of a given type in a single override block is the one that is used for that tag.

Component

A subtitle event is composed of three components. The first component, f is the fill, or inner text. The second component, o, is the outline/border component. The final component, s, is the shadow.

Lowercase f, o, and s are the only values that are valid components. Any other value (including a blank argument) will be treated as invalid syntax (resulting in the tag being ignored). Please note this is different from most fields, where a blank argument will result in the current value.

Color

Color values come in three flavors: RRGGBB, RRGGBBAA, and AA.

All three are hexidecimal byte representation with a leading #. Values may be upper or lower case.

Unlike old ASS, an alpha value of 00 is completely transparent and an alpha value of FF is completely opaque.

Examples:

RRGGBB: #9999CC - in decimal, rgb(153,153,204)

RRGGBBAA: #9999CCBF - the above, but 25% transparent

AA: #40 - 75% transparent

String

A string is an unquoted collection of characters. To disambiguate from other types, a string must not start with +, -, [0-9], , or #. All commas in strings must be escaped \, to avoid conflicts with tag argument delimitation. (TODO: can they begin with \?)

Override Tag Defintions

There are two types of override tags: global and positional. When the line is parsed, if it contains multiple global tags of the same type, the last such one in the entire line will be used. Positional tags are treated similarly within the scope a single tag block. If a positional tag appears more than once in a tag block (or multiple consecutive tag blocks), the last instance will be used.

Additionally, the symbols ❌ and ⭕ are used to denote whether or not a particular tag can be transformed with \t. ❌ means a tag cannot be transformed, and ⭕ means it can.

Arguments will be separated with commas, with each argument's type and default value inside braces, separated by a comma. If no default value is listed, there should be a chart directly below. If a type is followed by |percent, that indicates that a percent can be specified which will be converted to the former type. If two arguments deal with different parameters, the parameter will be specified after a :.

If there is only one possible combination of arguments, they will be listed in the tag definition's title. Otherwise, each possible combination will be listed below, with the differences explained.

Unless specifically noted, tags that accept integer/float/percent values will accept mixed versions of the arguments.

Example

{\shad(5)}Shadow of 5{\shad(2,60%)}x-shadow of 2, y-shadow of 3

Examples

{\tag([float|percent,0], [string,])} This means that the tag \tag takes two arguments. The first can be either a float or a percent, with the default at 0. The second argument is a string, with the default value being empty.

{\tag}

\tag([integer,0])

Description here.

\tag([boolean,-])

Description here too.

This means that the \tag takes two possibile argument types, an integer and a boolean. The former defaults to 0 while the latter defaults to false.

Positional Tags

Italic - \i([boolean,-])

Set italics on or off. If a font family is not available, faux italic will be used.

(TODO: faux italic specification.)

Example:

{\i(+)}This is italic. {\i(-)}This is not.

Bold - \b

\b([boolean,-])

Set bold on or off. Usually a weight of 700.

\b([integer,0])

Set the font to a specific weight.

If a font family is not available or the specified weight is not available, faux bold is used.

(TODO: faux bold specification.) (TODO: scenarios to consider- both fuax italics and bold application order, family with only bold and italics, not both, which is faux?)

Example:

{\b(+)}This is bold. {\b(600)}This is semibold.

Underline - \u([float:h,0])

Creates an underline originating at the font baseline h pixels tall.

Example:

{\u(2)}This is underlined. {\u(0)}This is not.

Strikethrough - \strike([float:h,0])

Creates a strikethrough halfway between the font baseline and cap height h pixels tall.

Example:

{\s(5.5)}This has thick strikethrough. {\s(0)}This does not have any.

Outline Size - \bord

\bord([float|percent,0])

Sets a specific outline size for both x and y.

\bord([float|percent:x,0],[float|percent:y,0])

Sets specific outline sizes for x and y independently. Accepts blank arguments. Both values are set relative to viewport height.

If a run has a \bord value of 0, all tags targeting the run's second component will do nothing.

Example:

{\bord(3)}This outline is offset by 3 horizontally and 3 vertically. {\bord(2.15,)}This outline is offset by 2.15 horizontally and 3 vertically. {\bord(1,2)}This outline is offset by 1 horizontally and 2 vertically.

Shadow Offset - \shad

\shad([float|percent,0])

Sets a specific shadow offset for both x and y.

\shad([float|percent:x,0],[float|percent:y,0])

Sets specific shadow offsets for x and y independently. Accepts blank arguments. Both values are set relative to viewport height.

If a run has a \shad value of 0, all tags targeting the run's second component will do nothing.

The shadow is offset after all other rendering is done, so these values are unaffected by e.g. rotation. Positive x values correspond to a leftward offset and positive y values correspond to a downward offset.

The shadow offset does not affect any other attributes of the line, especially its rotation origin.

Example:

{\shad(3)}This shadow is offset by 3 horizontally and 3 vertically. {\shad(2.15,)}This shadow is offset by 2.15 horizontally and 3 vertically. {\shad(1,2)}This shadow is offset by 1 horizontally and 2 vertically.

Blur Edge - \be([float|percent,0)

Sets a Gaussian blur on the composited line, blurring the edge. Radius is specified relative to the viewport height. This is applied after all components have been individually blurred.

Example:

`{\be1}Blurry{\be5}way blurry

Blur Component - \blur

\blur([float|percent,0])

Sets a Gaussian blur on the composited line. Each component is individually blurred. Radius is specified relative to the viewport height. (TODO: figure out how this actually works, because of transparency on fill)

\blur([component,f],[float|percent,0])

Sets the Gaussian blur of a specific component.

(TODO: specify how to calculate the coefficient)

Example:

{\shad(3)\blur(1)}Pretty blurry {\blur(s,2.5)}with an extra blurry shadow.

Font Name - \fn([string,Arial])

See rcombs's font proposal

Example:

{\fn(Arial)}I am in Arial. {\fn(Comic Sans)}I am popular.

Scale - \scale

\scale([float|percent,100%])

Sets the scale of the line.

\scale([float|percent:x,100%],[float|percent:y,100%])

Sets the x and y scale of the line independently. Accepts blank arguments.

(TODO: implementation details. There is no font size tag as in old ASS. All fonts are rendered at a specific size e.g. 200, and then scaled as necessary. This may actually be a terrible idea. this seems like a bad idea, especially when coupled with the distinction between float|h and float|percent i also don't care for this idea but we need to decide)

Font Spacing - \fsp

\fsp([float|percent,0])

Sets additional horizontal spacing between characters. The value specifies the number of pixels to add between consecutive characters. May be negative. (TODO: what happens if you set this to a very large negative number?)

\fsp([float|percent:h,0],[float|percent:v,0])

The first argument sets additional horizontal spacing between characters. The second sets additional vertical spacing between lines. Because this is a positional tag, the vertical spacing that is actually used for a given line is the maximum spacing value in that line.

Example:

{\fsp(-10)}These letters are very close together.

Rotation - \rot

\rot([float|percent,0])

Sets rotation around the z-axis. This is special-cased because it is the most common, and is not a perspective rotation.

\rot([float|percent:x,0],[float|percent:y,0])

Sets rotation around the axis defined as the x (horizontal) and y (vertical). Accepts blank arguments.

All values are given in degrees from the positive x and y axes respectively, increasing counterclockwise. The transformations are applied in the listed order.

Example:

{\rot(45)}A 45 degree angle. {\rot(50%)}A 22.5 degree angle.

Shearing - \shear([float|percent:x,0],[float|percent:y,0])

Sets the shear of a the line. Shear transforms are applied before rotations.

Unlike old ASS, changing the y shear does not reset the baseline.

(TODO: ASS shear values are normalized such that a value of 1 shears a line by its height (x-shear) or width (y-shear), creating a 45-degree angle along the sheared sides. This scale is very small compared to other tags. Renormalizing so e.g. 100 maps to a 45-degree angle may be desirable. Additionally, ASS shear is calculated relative to the top- left of a line, regardless of its origin. I think it should at least be affected by alignment. Also math.)

Example:

{\shear(1,)}sheared {\shear(,1)}invisible

Color and Alpha - \c

\c([color])
\c([component],[color])

Default values:

component color
f #FFFFFF00
o #00000000
s #00000080

Sets the color/alpha of the specified component to given color/alpha. If no component is specified, the change is applied to all of them after compositing.

Recall that the color type can specify just color, color+alpha, or just alpha. In the case that the value provided specifies only color or only alpha, the unspecified attribute is unchanged from what it was previously. Alpha is applied only to the composited glyph so that shadow will not bleed through the outline or center. If the old ASS behavior is desired, it can be accomplished by layering events.

Example:

{\c(#FF0000)}Red {\c(#80)} and translucent. {\c(#00FF00BC)} Green.

Insert Style - \style([string,Default],[boolean,-]) ❌?

Effectively inserts the tags specified by the named style in place of the style tag. Because lines do not have a default style associated with them, a name must be supplied. Note that this does NOT reset the values of tags that aren't contained within the named style.

This tag can appear in styles. When used in styles, it can only reference styles that have already been defined.

If the boolean is set to true, this tag resets all override values to their defaults and then applies values from the named style to those defaults.

Transform Tags - \t

\t([integer|percent:start],[integer|percent:end],[float:accel],[effects])
\t([integer|percent:start],[integer|percent:end],[effects])
\t([float:accel],[effects])
\t([effects])

Specifies a transformation from time start to time end (milliseconds, relative to the start time of the line.) If end is explicitly 0, it is set to the duration of the line. In the forms that they are omitted, start defaults to 0 and end defaults to the duration of the line. If start and end are supplied as percent values, they refer to percent of the line's length (the actual value used is math.floor(line.duration*percent), where line.duration is in milliseconds).

accel is a floating point acceleration value that must be greater than 0. Its default value is 1 (a linear transform).

effects is a list of fully-qualified, transformable override tags.

All of the provided tags are transformed from their initial state (their value immediately before the \t). The current (render) time, start and end times are used to calculate a normalized progress in [0,1]. The linear progress is then raised to the accel power to calculate the actual progress.

Perhaps more intelligibly, the above in psuedocode:

progress = (currentTime-start)/(end-start)
progress = math.pow(progress,accel)
value = (1-progress)*initialValue + progress*finalValue

Note that currentTime is relative to the start time of the line.

Transforms are evaluated sequentially. An example follows:

{\bord(5)\t(0,5,\bord(10))\t(1,6,\bord(0))}Example

0ms after the start of the line, the first transform would evaluate to:

progress = (0-0)/(5-0) = 0
value = (1-0)*5 + 0*10 = 5

and the second transform would evaluate to:

progress = (0-1)/(6-1) = 0
value = (1-0)*5 + 0*0 = 5

Resulting in the line being equivalent to:

{\bord(5)}Example

1ms after the start of the line, the first transform would evaluate to:

progress = (1-0)/(5-0) = 1/5 = 0.2
value = (1-0.2)*5 + 0.2*10 = 4 + 2 = 6

and the second transform would evaluate to:

progress = (1-1)/(6-1) = 0
value = (1-0)*6 + 0*0 = 6

Resulting in the line being equivalent to:

{\bord(6)}Example

2ms after the start of the line, the first transform would evaluate to:

progress = (2-0)/(5-0) = 2/5 = 0.4
value = (1-0.4)*5 + 0.4*10 = 3 + 4 = 7

and the second transform would evaluate to:

progress = (2-1)/(6-1) = 1/5 = 0.2
value = (1-0.2)*7 + 0.2*0 = 5.6

Resulting in the line being equivalent to:

{\bord(5.6)}Example

And so on. If currentTime is greater than end, the transform evaluates to effects.

Global Tags

Position - \pos([float:x],[float:y])

Same as old ASS.

(TODO: write real specification. Right-hand coordinate system pls)

Origin - \org([float:x],[float:y])

Default Values: Specified by the position.

Same as old ASS.

(TODO: write real specification)

Alignment - \a([integer,2])

Default values: (key: (l|r|t|b)m = (left|right|top|bottom) margin, (w|h) = (ScriptResX|ScriptResY))

Alignment x y
1 lm h-bm
2 w/2+lm-rm h-bm
3 w-rm h-bm
4 lm h/2+tm-bm
5 w/2+lm-rm h/2+tm-bm
6 w-rm h/2+tm-bm
7 lm tm
8 w/2+lm-rm tm
9 w-rm tm

Margin - \margin

\margin([float|percent])
\margin([float|percent:vert],[float|percent:horiz])
\margin([float|percent:top],[float|percent:horiz],[float|percent:bottom])
\margin([float|percent:top],[float|percent:left],[float|percent:bottom],[float|percent:right])

Default Values: Vertical: 5% Horizontal: 9%

First tag just affects horizontal. TODO explain this, allow both percent & canvas units

Layer `\lay([integer,0])

TODO

Clone this wiki locally