A library to render ASS subtitles on HTML5 video in the browser.

libjass is a JavaScript library written in TypeScript to render ASS subs on HTML5 video in the browser. Check out the demo.

  • libjass requires no tweaks to the ASS file from the original video.

  • libjass uses the browser's native CSS engine by converting the components of each line in the ASS script into a series of styled <div> and <span> elements. This allows all the layout and rendering to be handled by the browser instead of requiring complex and costly drawing and animation code. For example, libjass uses CSS3 animations to simulate tags such as \fad. While a canvas-drawing library would have to re-draw such a subtitle on the canvas for every frame of the video, libjass only renders it once and lets the browser render the fade effect.

As a result, libjass is able to render subtitles with very low CPU usage. The downside to libjass's aproach is that it is hard (and potentially impossible) to map all effects possible in ASS (using \t, ASS draw) etc. into DOM elements. As of now, the subset of tags supported by libjass has no such problems.

You can install the latest release of libjass using npm with npm install libjass or using bower with bower install<release name>/ Inside the package, you will find libjass.js and libjass.css, which you need to load on your website with your video.

Alternatively, you can build libjass from source by cloning this repository and running npm install. This will install the dependencies and run the build. libjass.js and libjass.css will be found in the lib/ directory.

Only libjass.js and libjass.css are needed to use libjass on your website. The other files are only used during the build process and you don't need to deploy them to your website.

  • The src/ directory contains the source of libjass. They are TypeScript files and get compiled into JavaScript for the browser using the TypeScript compiler.

  • gulpfile.js is the build script. The build command will use this script to build libjass.js. The gulplib/ directory contains other files used for the build.

  • The tests/ directory contains unit and functional tests.

  • The lib/ directory contains libjass.js and libjass.css. You will need to deploy these to your website.

The API documentation is linked in the Links section below. Here's an overview:

  • The ASS.fromUrl() function takes in a URL to an ASS script and returns a promise that resolves to an ASS object. This ASS object represents the script properties, the line styles and dialogue lines in it. Alternatively, you can use ASS.fromString() to convert a string of the script contents into an ASS object.

  • Next, you initialize a renderer to render the subtitles. libjass ships with an easy-to-use renderer, the DefaultRenderer. It uses information from the ASS object to build up a series of div elements around the video tag. There is a wrapper (.libjass-subs) containing div's corresponding to the layers in the ASS script, and each layer has div's corresponding to the 9 alignment directions. libjass.css contains styles for these div's to render them at the correct location.

  • The renderer uses window.requestAnimationFrame as a source of timer ticks. In each tick, it determines the set of dialogues to be shown at the current video time, renders each of them as a div, and appendChild's the div into the appropriate layer+alignment div.

  • The renderer can be told to dynamically change the size of the subtitles based on user input by calling WebRenderer.resize() DefaultRenderer also handles resizing the subtitles automatically when the user clicks the browser's native fullscreen-video button.

  • Lastly, the renderer contains an implementation of preloading fonts before playing the video. It uses a map of font names to URLs - this map can be conveniently created from a CSS file containing @font-face rules using RendererSettings.makeFontMapFromStyleElement()

  • For an example of using libjass, check out the demo. It has comments explaining basic usage and pointers to some advanced usage.

  • libjass uses some ES5 features like getters and setters (via Object.defineProperty), and assumptions like the behavior of parseInt with leading zeros. It cannot be used with an ES3 environment.

  • libjass will use ES6 Set, Map and Promise if they're available on the global object. If they're not present, it will use its own minimal internal implementations. If you have implementations of these that you would like libjass to use but don't want to register them on the global object, you can provide them to libjass specifically by setting the libjass.Set, libjass.Map and libjass.Promise properties.

  • AutoClock and VideoClock use window.requestAnimationFrame to generate clock ticks.

  • WebRenderer and DefaultRenderer use SVG filter effects for HTML to render outlines and blur. This feature is not available on all browsers, so you can tell them to fall back to more widely available CSS methods by setting the RendererSettings.enableSvg property to false.

  • WebRenderer and DefaultRenderer use CSS3 animations for effects like \mov and \fad.

libjass's parser works in node. Entire scripts can be parsed via ASS.fromString()

> var libjass = require("libjass")
> var ass; libjass.ASS.fromString(fs.readFileSync("mysubs.ass", "utf8")).then(function (result) { ass = result; })
> ass.dialogues.length
> ass.dialogues[0].toString()
'#0 [646.460-652.130] {\\fad(200,0)}Sapien rhoncus, suscipit posuere in nunc pellentesque'
> var parts = ass.dialogues[0].parts
> parts.length
> parts[0] instanceof
> parts[0].toString()
'Fade { start: 0.2, end: 0 }'

libjass.parser.parse parses the first parameter using the second parameter as the rule name. For example, the dialogueParts rule can be used to get an array of objects that represent the parts of an ASS dialogue line.

> var parts = libjass.parser.parse("{\\an8}Are {\\i1}you{\\i0} the one who stole the clock?!", "dialogueParts")
> parts.join(" ")
'Alignment { value: 8 } Text { value: Are  } Italic { value: true } Text { value: you } Italic { value: false } Text { value:  the one who stole the clock?! }'
> parts.length
> parts[0].toString()
'Alignment { value: 8 }'
> parts[0] instanceof
> parts[0].value

The rule names are derived from the methods on the ParserRun class.

See the tests, particularly the ones in tests/unit/miscellaneous.js, for examples.

Yes! Feature requests, suggestions, bug reports and pull requests are welcome! I'm especially looking for details and edge-cases of the ASS syntax that libjass doesn't support.

You can also join the IRC channel in the links section below and ask any questions.

  • Styles: Italic, Bold, Underline, StrikeOut, FontName, FontSize, ScaleX, ScaleY, Spacing, PrimaryColor, OutlineColor, BackColor, Outline, Shadow, Alignment, MarginL, MarginR, MarginV
  • Tags: \i, \b, \u, \s, \bord, \xbord, \ybord, \shad, \xshad, \yshad, \be, \blur, \fn, \fs, \fscx, \fscy, \fsp, \frx, \fry, \frz, \fr, \fax, \fay, \c, \1c, \3c, \4c, \alpha, \1a, \3a, \4a, \an, \a, \k, \q, \r, \pos, \move, \fad, \fade, \p
  • Custom fonts, using CSS web fonts.
  • Unsupported tags: \fe, \2c, \2a, \K, \kf, \ko, \org, \t, \clip, \iclip
  • \an4, \an5, \an6 aren't positioned correctly.
  • Smart line wrapping is not supported. Such lines are rendered as wrapping style 1 (end-of-line wrapping).
  • Lines with multiple rotations aren't rotated the same as VSFilter or libass. See #14
Copyright 2013 Arnav Singh
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
See the License for the specific language governing permissions and
limitations under the License.