{"id":20188512,"url":"https://github.com/weizhenye/ass","last_synced_at":"2026-02-21T20:18:00.534Z","repository":{"id":14177521,"uuid":"16883695","full_name":"weizhenye/ASS","owner":"weizhenye","description":"A lightweight JavaScript ASS subtitle renderer","archived":false,"fork":false,"pushed_at":"2025-03-09T13:31:12.000Z","size":601,"stargazers_count":589,"open_issues_count":7,"forks_count":85,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-05-14T18:04:39.182Z","etag":null,"topics":["ass","subtitle"],"latest_commit_sha":null,"homepage":"https://ass.js.org","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/weizhenye.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-02-16T11:44:46.000Z","updated_at":"2025-05-14T15:05:29.000Z","dependencies_parsed_at":"2022-07-10T00:16:36.109Z","dependency_job_id":"a981b837-a248-4eba-8e11-9e4dfd659aa4","html_url":"https://github.com/weizhenye/ASS","commit_stats":{"total_commits":126,"total_committers":4,"mean_commits":31.5,"dds":"0.023809523809523836","last_synced_commit":"e6a3605a2343655d9ef80bdd7e9fe92f92edca22"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weizhenye%2FASS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weizhenye%2FASS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weizhenye%2FASS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/weizhenye%2FASS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/weizhenye","download_url":"https://codeload.github.com/weizhenye/ASS/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254198514,"owners_count":22030965,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ass","subtitle"],"created_at":"2024-11-14T03:29:27.215Z","updated_at":"2026-02-21T20:18:00.529Z","avatar_url":"https://github.com/weizhenye.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ASS.js\n\n[![GitHub Action](https://img.shields.io/github/actions/workflow/status/weizhenye/ASS/ci.yml?logo=github)](https://github.com/weizhenye/ASS/actions)\n[![Codecov](https://img.shields.io/codecov/c/gh/weizhenye/ASS?logo=codecov)](https://codecov.io/gh/weizhenye/ASS)\n[![License](https://img.shields.io/npm/l/assjs)](https://github.com/weizhenye/assjs/blob/master/LICENSE)\n[![File size](https://img.shields.io/bundlephobia/minzip/assjs)](https://bundlephobia.com/result?p=assjs)\n\n\u003cspan\u003e・\u003c/span\u003e\n\u003ca href=\"https://ass.js.org/\"\u003eOnline Demo\u003c/a\u003e\n\u003cspan\u003e・\u003c/span\u003e\n\u003ca href=\"https://github.com/weizhenye/ASS/wiki/ASS-%E5%AD%97%E5%B9%95%E6%A0%BC%E5%BC%8F%E8%A7%84%E8%8C%83\"\u003eASS specs (zh-Hans)\u003c/a\u003e\n\u003cspan\u003e・\u003c/span\u003e\n\u003ca href=\"https://github.com/weizhenye/ass-compiler\"\u003eass-compiler\u003c/a\u003e\n\u003cspan\u003e・\u003c/span\u003e\n\nASS.js renders ASS subtitles on HTML5 video, with [almost full ASS features](https://github.com/weizhenye/ASS/wiki/Differences-with-Specs).\n\nIt's lightweight and suitable for web, **60x** smaller than WebAssembly solutions:\n| | Solution | Size |\n| - | - | - |\n| ASS.js | DOM | ![](https://img.shields.io/github/size/weizhenye/ASS/dist%2Fass.min.js?label=main)\n| [JavascriptSubtitlesOctopus](https://github.com/libass/JavascriptSubtitlesOctopus) | WebAssembly | ![](https://img.shields.io/github/size/libass/JavascriptSubtitlesOctopus/assets%2Fjs%2Fsubtitles-octopus.js?branch=gh-pages\u0026label=main) ![](https://img.shields.io/github/size/libass/JavascriptSubtitlesOctopus/assets%2Fjs%2Fsubtitles-octopus-worker.js?branch=gh-pages\u0026label=worker) ![](https://img.shields.io/github/size/libass/JavascriptSubtitlesOctopus/assets%2Fjs%2Fsubtitles-octopus-worker.wasm?branch=gh-pages\u0026label=wasm) |\n| [JASSUB](https://github.com/ThaUnknown/jassub) | WebAssembly | ![](https://img.shields.io/github/size/ThaUnknown/jassub/static%2Fsubtitles-octopus-worker.wasm?branch=gh-pages\u0026label=wasm) and [others](https://app.unpkg.com/jassub) |\n\nWebAssembly solutions also requires to set fallback font to avoid CJK characters turning into tofu, it's a huge cost for web. In ASS.js font fallback is handled by browser, it just works.\n\nHowever compared to WebAssembly solutions, it's almost impossible for DOM to render exactly same result in every pixels as VSFilter or libass, ASS.js will provide best efforts to accurate rendering.\n\n## Installation\n\n[![NPM Version](https://img.shields.io/npm/v/assjs?logo=npm)](https://www.npmjs.com/package/assjs)\n[![jsDelivr](https://img.shields.io/jsdelivr/npm/hm/assjs?logo=jsdelivr)](https://www.jsdelivr.com/package/npm/assjs)\n[![](https://img.shields.io/badge/unpkg-555?logo=unpkg)](https://unpkg.com/assjs/)\n\n```bash\nnpm install assjs\n```\n\nASS.js can be used as a JavaScript module:\n\n```html\n\u003cscript type=\"module\"\u003e\nimport ASS from '/path/to/assjs/dist/ass.min.js';\n\u003c/script\u003e\n```\n\nor a classic script:\n\n```html\n\u003cscript src=\"/path/to/assjs/dist/ass.global.min.js\"\u003e\u003c/script\u003e\n\u003cscript\u003e\nconsole.log(window.ASS);\n\u003c/script\u003e\n```\n\n## Usage\n\n```html\n\u003cdiv id=\"player\"\u003e\n  \u003cvideo id=\"video\" src=\"./example.mp4\"\u003e\u003c/video\u003e\n  \u003cdiv id=\"ass-container\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n```\n\n```js\nimport ASS from 'assjs';\n\nconst content = await fetch('/path/to/example.ass').then((res) =\u003e res.text());\nconst ass = new ASS(content, document.querySelector('#video'), {\n  container: document.querySelector('#ass-container'),\n});\n```\n\n`new ASS()` will append several elements to the container, and sync the render area's size with the video element. **You should set styles yourself to make sure the container is overlap on the video and match the position.** For example:\n\n```html\n\u003cdiv id=\"player\" style=\"position: relative;\"\u003e\n  \u003cvideo id=\"video\" src=\"./example.mp4\" style=\"position: absolute; top: 0; left: 0;\"\u003e\u003c/video\u003e\n  \u003cdiv id=\"ass-container\" style=\"position: absolute; top: 0; left: 0;\"\u003e\u003c/div\u003e\n\u003c/div\u003e\n```\n\nIf you click the native fullscreen button in video element, only `\u003cvideo\u003e` will be fullscreened, so ASS will not show. You should use a custom button and call `document.querySelector('#player').requestFullscreen()` to ensure ASS is contained.\n\n## API\n\n#### Initialization\n\n```js\nconst ass = new ASS(content, video, {\n  // Subtitles will display in the container.\n  container: document.getElementById('my-container'),\n\n  // see resampling API below\n  resampling: 'video_width',\n});\n```\n\n#### Show\n\n```js\nass.show();\n```\n\n#### Hide\n\n```js\nass.hide();\n```\n\n#### Destroy\n\n```js\nass.destroy();\n```\n\n#### Delay\n\n```js\n// Subtitles will be 5s later\nass.delay = 5;\n// Subtitles will be 3s earlier\nass.delay = -3;\n```\n\n#### Resampling\n\nWhen script resolution(PlayResX and PlayResY) don't match the video resolution, this API defines how it behaves. However, drawings and clips will be always depending on script origin resolution.\n\nThere are four valid values, we suppose video resolution is 1280x720 and script resolution is 640x480 in following situations:\n* `video_width`: Script resolution will set to video resolution based on video width. Script resolution will set to 640x360, and scale = 1280 / 640 = 2.\n* `video_height`(__default__): Script resolution will set to video resolution based on video height. Script resolution will set to 853.33x480, and scale = 720 / 480 = 1.5.\n* `script_width`: Script resolution will not change but scale is based on script width. So scale = 1280 / 640 = 2. This may causes top and bottom subs disappear from video area.\n* `script_height`: Script resolution will not change but scale is based on script height. So scale = 720 / 480 = 1.5. Script area will be centered in video area.\n\n```js\nass.resampling = 'video_width';\n```\n\n## Browser Compatibility\n\nASS.js uses many Web APIs to render subtitles, some features will be disabled if you use a old browser.\n\n| Feature | Web API | Chrome | Firefox | Safari |\n| - | - | - | - | - |\n| Auto resize | [ResizeObserver](https://caniuse.com/resizeobserver) | 64 | 69 | 13.1 |\n| `\\[i]clip` | [clip-path](https://caniuse.com/css-clip-path) and [path()](https://caniuse.com/mdn-css_types_basic-shape_path) | 88 | 97 | 13.1 |\n| Animations (`\\t`) | [registerProperty()](https://caniuse.com/mdn-api_css_registerproperty_static) | 78 | 128 | 16.4 |\n| accel in `\\t` | [linear()](https://caniuse.com/mdn-css_types_easing-function_linear-function) | 113 | 112 | 17.2 |\n| `\\q0` | [text-wrap: balance](https://caniuse.com/css-text-wrap-balance) | 114 | 121 | 17.5 |\n| `\\blur` with `\\bord0` | [round()](https://caniuse.com/mdn-css_types_round) | 125 | 118 | 15.4 |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweizhenye%2Fass","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fweizhenye%2Fass","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fweizhenye%2Fass/lists"}