├── .changeset ├── README.md └── config.json ├── .github ├── dependabot.yml └── workflows │ ├── main.yml │ └── publish.yml ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── rollup.config.js ├── src ├── ass.ts ├── renderer.ts ├── types.ts └── utils.ts ├── tsconfig.json └── tsup.config.ts /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@2.3.1/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "main", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: 'npm' 9 | directory: '/' # root 10 | schedule: 11 | interval: 'weekly' 12 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | 7 | jobs: 8 | build: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: pnpm/action-setup@v2 13 | with: 14 | version: latest 15 | - uses: actions/setup-node@v3 16 | with: 17 | node-version: 18.x 18 | cache: 'pnpm' 19 | 20 | - run: pnpm install --frozen-lockfile 21 | - run: pnpm run build 22 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | on: 3 | workflow_run: 4 | workflows: ['CI'] 5 | types: 6 | - completed 7 | push: 8 | branches: 9 | - 'main' 10 | 11 | concurrency: ${{ github.workflow }}-${{ github.ref }} 12 | 13 | jobs: 14 | publish: 15 | if: ${{ github.event.workflow_run.conclusion == 'success' }} 16 | runs-on: ubuntu-latest 17 | steps: 18 | - uses: actions/checkout@v3 19 | - uses: pnpm/action-setup@v2 20 | with: 21 | version: latest 22 | - uses: actions/setup-node@v3 23 | with: 24 | node-version: 18.x 25 | cache: 'pnpm' 26 | 27 | - run: pnpm install --frozen-lockfile 28 | - name: Create Release Pull Request or Publish 29 | id: changesets 30 | uses: changesets/action@v1 31 | with: 32 | publish: pnpm run release 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 35 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .changeset 2 | pnpm-lock.yaml 3 | tsconfig.json 4 | tsup.config.ts 5 | CHANGELOG.md 6 | .github 7 | src 8 | .prettierignore 9 | .prettierrc 10 | README.md 11 | rollup.config.js 12 | .gitmodules 13 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | /.changeset 5 | 6 | # Ignore files for PNPM, NPM and YARN 7 | pnpm-lock.yaml 8 | package-lock.json 9 | yarn.lock 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "tabWidth": 2, 4 | "useTabs": false, 5 | "singleQuote": true, 6 | "trailingComma": "none", 7 | "printWidth": 100 8 | } 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # ass-html5 2 | 3 | ## 0.5.3 4 | 5 | ### Patch Changes 6 | 7 | - b1053bf: [fix] single character color alternating not displayed 8 | 9 | ## 0.5.2 10 | 11 | ### Patch Changes 12 | 13 | - a325cfb: Custom animation support 14 | 15 | ## 0.5.1 16 | 17 | ### Patch Changes 18 | 19 | - 309ba25: NEW: Move Animation implemented 20 | 21 | BREAKING: Changing `LOGTYPE` from an emun to a bar simple type 22 | 23 | ## 0.5.0 24 | 25 | ### Minor Changes 26 | 27 | - 5d95b6a: Ass engine renderer rewrite 28 | 29 | ## 0.4.1 30 | 31 | ### Patch Changes 32 | 33 | - 90a8f29: removing `tsup` from dependencies 34 | 35 | ## 0.4.0 36 | 37 | ### Minor Changes 38 | 39 | - 3197954: Rendering encapsulation 40 | 41 | ## 0.3.6 42 | 43 | ### Patch Changes 44 | 45 | - 9e978ab: Adding text transparency 46 | 47 | ## 0.3.5 48 | 49 | ### Patch Changes 50 | 51 | - 8c59a89: Font vertical spacing & Text custom position improve 52 | 53 | ## 0.3.4 54 | 55 | ### Patch Changes 56 | 57 | - 0bdde5c: Custom Font Loading crash fixed 58 | 59 | ## 0.3.3 60 | 61 | ### Patch Changes 62 | 63 | - a45de93: - Font Vertical and Horizontal Transformation Support 64 | 65 | - Re-writing Core Part (Simplify) 66 | 67 | ## 0.3.2 68 | 69 | ### Patch Changes 70 | 71 | - 6278551: Uptade Modules to `mjs`, Fix import issues with cjs 72 | 73 | ## 0.3.1 74 | 75 | ### Patch Changes 76 | 77 | - 6ee8ac2: Lower the target es 78 | 79 | ## 0.3.0 80 | 81 | ### Minor Changes 82 | 83 | - 65d5e18: Adding custom fonts + Some bugs fixes 84 | 85 | ## 0.2.7 86 | 87 | ### Patch Changes 88 | 89 | - 53bbd52: Fix inline texts, correct tweaks tags application to font descriptor + Drawing text at a custom position improved 90 | 91 | ## 0.2.6 92 | 93 | ### Patch Changes 94 | 95 | - ea26665: Fix empty lines drawing 96 | 97 | ## 0.2.5 98 | 99 | ### Patch Changes 100 | 101 | - 5e1cb30: v0.2.5 102 | 103 | ## 0.2.4 104 | 105 | ### Patch Changes 106 | 107 | - 6dfddb2: Build for Web 108 | 109 | ## 0.2.4 110 | 111 | ### Patch Changes 112 | 113 | - a2719bb: Bug fixes in styled multilines (New way to draw text) 114 | 115 | ## 0.2.3 116 | 117 | ### Patch Changes 118 | 119 | - fc82eb5: Minor bug fixes 120 | 121 | ## 0.2.2 122 | 123 | ### Patch Changes 124 | 125 | - a51ae35: - Inline Changes in normal text display fix (with this bug, an inline transformation on a text while result in an overlapping on other drawn text) 126 | - Mutilines Texts Tweaks fix (End of Line Shifts) 127 | 128 | ## 0.2.1 129 | 130 | ### Patch Changes 131 | 132 | - fe65d34: Adding Inline Multi-Styling 133 | 134 | ## 0.2.0 135 | 136 | ### Minor Changes 137 | 138 | - 8a05416: Making `ass-compiler` (https://github.com/weizhenye/ass-compiler) internal. Using only the parse method 139 | 140 | ## 0.1.0 141 | 142 | ### Minor Changes 143 | 144 | - f0a1538: Adding Some Tweaks 145 | 146 | ## 0.0.1 147 | 148 | ### Patch Changes 149 | 150 | - cc7c0e1: Basic futures added 151 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023-present luxluth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | # ass-html5 4 | 5 | Display ASS/SSA subtitles on html5 videos 6 | 7 | ![CI workflow](https://github.com/luxluth/ass-html5/actions/workflows/main.yml/badge.svg) 8 | ![Publish workflow](https://github.com/luxluth/ass-html5/actions/workflows/publish.yml/badge.svg) 9 | ![License](https://img.shields.io/github/license/luxluth/ass-html5?color=blue) 10 | ![npm bundle size](https://img.shields.io/bundlephobia/min/ass-html5) 11 | ![npm](https://img.shields.io/npm/v/ass-html5?logo=npm&color=white&link=https%3A%2F%2Fwww.npmjs.com%2Fpackage%2Fass-html5) 12 | 13 |
14 | 15 | ## Table of Contents 16 | 17 | - [ass-html5](#ass-html5) 18 | - [Table of Contents](#table-of-contents) 19 | - [Installation](#installation) 20 | - [Usage](#usage) 21 | - [Options](#options) 22 | - [Simple HTML](#simple-html) 23 | - [Svelte and Plry](#svelte-and-plry) 24 | - [videojs](#videojs) 25 | - [Credits](#credits) 26 | 27 | ## Installation 28 | 29 | ```bash 30 | pnpm add ass-html5 31 | ``` 32 | 33 | ## Usage 34 | 35 | ### Options 36 | 37 | | option | description | required | type | default | 38 | | :-----: | :---------------------------------------------------------------------------------------------------------: | :------: | :---------------------------: | :-------------------: | 39 | | assText | The ass text string | ✅ | `string` | `undefined` | 40 | | video | The video to display the subtile on. Can be either an `HTMLVideoElement` or `string` (html query selector ) | ✅ | `HTMLVideoElement` / `string` | `undefined` | 41 | | fonts | Custom fonts to load | 🚫 | [`Font[]`](src/ass.ts#L72) | `undefined` | 42 | | zIndex | zIndex of the rendering frame | 🚫 | `number` | Drawn after the video | 43 | | onReady | A Callback that is invoked when the preprocess of the ass text by render is done | 🚫 | `() => void` | `undefined` | 44 | | logging | Type of logging (experimental) | 🚫 | [`LOGTYPE`](src/ass.ts#L44) | `LOGTYPE.DISABLE` | 45 | 46 | ### Simple HTML 47 | 48 | > [!NOTE] 49 | > The simple `video` tag element, in fullscreen mode, the position of the video is absolutely on top of any element. 50 | > No other element can go on top of it. 51 | > 52 | > It's therefore recommended to use a third party player rather than the native one. You can see an example with [plry](https://github.com/sampotts/plyr) [here](#svelte-and-plry). 53 | 54 | ```html 55 | 56 | ``` 57 | 58 | ```html 59 | 60 | ``` 61 | 62 | ```html 63 | 75 | ``` 76 | 77 | ### [Svelte](https://github.com/sveltejs/svelte) and [Plry](https://github.com/sampotts/plyr) 78 | 79 | ```svelte 80 | 100 | 101 |
102 | 103 | 112 |
113 | ``` 114 | 115 | ### [videojs](https://github.com/videojs/video.js) 116 | 117 | In the `head` : 118 | 119 | ```html 120 | 121 | 122 | 123 | ``` 124 | 125 | In the `body` : 126 | 127 | ```html 128 | 139 | ``` 140 | 141 | In the `script` tag : 142 | 143 | ```html 144 | 162 | ``` 163 | 164 | --- 165 | 166 | # Credits 167 | 168 | Thanks to the [ass-compiler](https://github.com/weizhenye/ass-compiler/) by weizhenye. 169 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ass-html5", 3 | "version": "0.5.3", 4 | "description": "Display ASS/SSA subtitles on html5 videos", 5 | "main": "dist/ass.js", 6 | "module": "dist/ass.mjs", 7 | "types": "dist/ass.d.ts", 8 | "browser": "dist/ass.min.js", 9 | "scripts": { 10 | "build": "pnpm lint && pnpm run build:normal && pnpm run build:minify", 11 | "build:normal": "tsup", 12 | "build:minify": "rollup -c --bundleConfigAsCjs", 13 | "dev": "tsup --watch", 14 | "release": "pnpm run build && changeset publish", 15 | "lint": "tsc", 16 | "format": "prettier --write ." 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/luxluth/ass-html5.git" 21 | }, 22 | "keywords": [ 23 | "ASS", 24 | "SSA", 25 | "subtitles", 26 | "aegisub", 27 | "libass" 28 | ], 29 | "author": "luxluth", 30 | "license": "MIT", 31 | "bugs": { 32 | "url": "https://github.com/luxluth/ass-html5/issues" 33 | }, 34 | "homepage": "https://github.com/luxluth/ass-html5#readme", 35 | "devDependencies": { 36 | "@changesets/cli": "^2.27.12", 37 | "@rollup/plugin-commonjs": "^28.0.2", 38 | "@rollup/plugin-node-resolve": "^16.0.0", 39 | "@rollup/plugin-terser": "^0.4.4", 40 | "@rollup/plugin-typescript": "^12.1.2", 41 | "@types/node": "^22.13.0", 42 | "ass-compiler": "^0.1.15", 43 | "prettier": "^3.4.2", 44 | "rollup": "^4.34.1", 45 | "terser": "^5.37.0", 46 | "tslib": "^2.8.1", 47 | "tsup": "^8.3.6", 48 | "typescript": "^5.7.3" 49 | }, 50 | "pnpm": { 51 | "onlyBuiltDependencies": [ 52 | "esbuild" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: 10 | devDependencies: 11 | '@changesets/cli': 12 | specifier: ^2.27.12 13 | version: 2.28.1 14 | '@rollup/plugin-commonjs': 15 | specifier: ^28.0.2 16 | version: 28.0.2(rollup@4.34.8) 17 | '@rollup/plugin-node-resolve': 18 | specifier: ^16.0.0 19 | version: 16.0.0(rollup@4.34.8) 20 | '@rollup/plugin-terser': 21 | specifier: ^0.4.4 22 | version: 0.4.4(rollup@4.34.8) 23 | '@rollup/plugin-typescript': 24 | specifier: ^12.1.2 25 | version: 12.1.2(rollup@4.34.8)(tslib@2.8.1)(typescript@5.7.3) 26 | '@types/node': 27 | specifier: ^22.13.0 28 | version: 22.13.5 29 | ass-compiler: 30 | specifier: ^0.1.15 31 | version: 0.1.15 32 | prettier: 33 | specifier: ^3.4.2 34 | version: 3.5.2 35 | rollup: 36 | specifier: ^4.34.1 37 | version: 4.34.8 38 | terser: 39 | specifier: ^5.37.0 40 | version: 5.39.0 41 | tslib: 42 | specifier: ^2.8.1 43 | version: 2.8.1 44 | tsup: 45 | specifier: ^8.3.6 46 | version: 8.3.6(typescript@5.7.3)(yaml@2.4.2) 47 | typescript: 48 | specifier: ^5.7.3 49 | version: 5.7.3 50 | 51 | packages: 52 | 53 | '@babel/runtime@7.26.9': 54 | resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} 55 | engines: {node: '>=6.9.0'} 56 | 57 | '@changesets/apply-release-plan@7.0.10': 58 | resolution: {integrity: sha512-wNyeIJ3yDsVspYvHnEz1xQDq18D9ifed3lI+wxRQRK4pArUcuHgCTrHv0QRnnwjhVCQACxZ+CBih3wgOct6UXw==} 59 | 60 | '@changesets/assemble-release-plan@6.0.6': 61 | resolution: {integrity: sha512-Frkj8hWJ1FRZiY3kzVCKzS0N5mMwWKwmv9vpam7vt8rZjLL1JMthdh6pSDVSPumHPshTTkKZ0VtNbE0cJHZZUg==} 62 | 63 | '@changesets/changelog-git@0.2.1': 64 | resolution: {integrity: sha512-x/xEleCFLH28c3bQeQIyeZf8lFXyDFVn1SgcBiR2Tw/r4IAWlk1fzxCEZ6NxQAjF2Nwtczoen3OA2qR+UawQ8Q==} 65 | 66 | '@changesets/cli@2.28.1': 67 | resolution: {integrity: sha512-PiIyGRmSc6JddQJe/W1hRPjiN4VrMvb2VfQ6Uydy2punBioQrsxppyG5WafinKcW1mT0jOe/wU4k9Zy5ff21AA==} 68 | hasBin: true 69 | 70 | '@changesets/config@3.1.1': 71 | resolution: {integrity: sha512-bd+3Ap2TKXxljCggI0mKPfzCQKeV/TU4yO2h2C6vAihIo8tzseAn2e7klSuiyYYXvgu53zMN1OeYMIQkaQoWnA==} 72 | 73 | '@changesets/errors@0.2.0': 74 | resolution: {integrity: sha512-6BLOQUscTpZeGljvyQXlWOItQyU71kCdGz7Pi8H8zdw6BI0g3m43iL4xKUVPWtG+qrrL9DTjpdn8eYuCQSRpow==} 75 | 76 | '@changesets/get-dependents-graph@2.1.3': 77 | resolution: {integrity: sha512-gphr+v0mv2I3Oxt19VdWRRUxq3sseyUpX9DaHpTUmLj92Y10AGy+XOtV+kbM6L/fDcpx7/ISDFK6T8A/P3lOdQ==} 78 | 79 | '@changesets/get-release-plan@4.0.8': 80 | resolution: {integrity: sha512-MM4mq2+DQU1ZT7nqxnpveDMTkMBLnwNX44cX7NSxlXmr7f8hO6/S2MXNiXG54uf/0nYnefv0cfy4Czf/ZL/EKQ==} 81 | 82 | '@changesets/get-version-range-type@0.4.0': 83 | resolution: {integrity: sha512-hwawtob9DryoGTpixy1D3ZXbGgJu1Rhr+ySH2PvTLHvkZuQ7sRT4oQwMh0hbqZH1weAooedEjRsbrWcGLCeyVQ==} 84 | 85 | '@changesets/git@3.0.2': 86 | resolution: {integrity: sha512-r1/Kju9Y8OxRRdvna+nxpQIsMsRQn9dhhAZt94FLDeu0Hij2hnOozW8iqnHBgvu+KdnJppCveQwK4odwfw/aWQ==} 87 | 88 | '@changesets/logger@0.1.1': 89 | resolution: {integrity: sha512-OQtR36ZlnuTxKqoW4Sv6x5YIhOmClRd5pWsjZsddYxpWs517R0HkyiefQPIytCVh4ZcC5x9XaG8KTdd5iRQUfg==} 90 | 91 | '@changesets/parse@0.4.1': 92 | resolution: {integrity: sha512-iwksMs5Bf/wUItfcg+OXrEpravm5rEd9Bf4oyIPL4kVTmJQ7PNDSd6MDYkpSJR1pn7tz/k8Zf2DhTCqX08Ou+Q==} 93 | 94 | '@changesets/pre@2.0.2': 95 | resolution: {integrity: sha512-HaL/gEyFVvkf9KFg6484wR9s0qjAXlZ8qWPDkTyKF6+zqjBe/I2mygg3MbpZ++hdi0ToqNUF8cjj7fBy0dg8Ug==} 96 | 97 | '@changesets/read@0.6.3': 98 | resolution: {integrity: sha512-9H4p/OuJ3jXEUTjaVGdQEhBdqoT2cO5Ts95JTFsQyawmKzpL8FnIeJSyhTDPW1MBRDnwZlHFEM9SpPwJDY5wIg==} 99 | 100 | '@changesets/should-skip-package@0.1.2': 101 | resolution: {integrity: sha512-qAK/WrqWLNCP22UDdBTMPH5f41elVDlsNyat180A33dWxuUDyNpg6fPi/FyTZwRriVjg0L8gnjJn2F9XAoF0qw==} 102 | 103 | '@changesets/types@4.1.0': 104 | resolution: {integrity: sha512-LDQvVDv5Kb50ny2s25Fhm3d9QSZimsoUGBsUioj6MC3qbMUCuC8GPIvk/M6IvXx3lYhAs0lwWUQLb+VIEUCECw==} 105 | 106 | '@changesets/types@6.1.0': 107 | resolution: {integrity: sha512-rKQcJ+o1nKNgeoYRHKOS07tAMNd3YSN0uHaJOZYjBAgxfV7TUE7JE+z4BzZdQwb5hKaYbayKN5KrYV7ODb2rAA==} 108 | 109 | '@changesets/write@0.4.0': 110 | resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} 111 | 112 | '@esbuild/aix-ppc64@0.24.2': 113 | resolution: {integrity: sha512-thpVCb/rhxE/BnMLQ7GReQLLN8q9qbHmI55F4489/ByVg2aQaQ6kbcLb6FHkocZzQhxc4gx0sCk0tJkKBFzDhA==} 114 | engines: {node: '>=18'} 115 | cpu: [ppc64] 116 | os: [aix] 117 | 118 | '@esbuild/android-arm64@0.24.2': 119 | resolution: {integrity: sha512-cNLgeqCqV8WxfcTIOeL4OAtSmL8JjcN6m09XIgro1Wi7cF4t/THaWEa7eL5CMoMBdjoHOTh/vwTO/o2TRXIyzg==} 120 | engines: {node: '>=18'} 121 | cpu: [arm64] 122 | os: [android] 123 | 124 | '@esbuild/android-arm@0.24.2': 125 | resolution: {integrity: sha512-tmwl4hJkCfNHwFB3nBa8z1Uy3ypZpxqxfTQOcHX+xRByyYgunVbZ9MzUUfb0RxaHIMnbHagwAxuTL+tnNM+1/Q==} 126 | engines: {node: '>=18'} 127 | cpu: [arm] 128 | os: [android] 129 | 130 | '@esbuild/android-x64@0.24.2': 131 | resolution: {integrity: sha512-B6Q0YQDqMx9D7rvIcsXfmJfvUYLoP722bgfBlO5cGvNVb5V/+Y7nhBE3mHV9OpxBf4eAS2S68KZztiPaWq4XYw==} 132 | engines: {node: '>=18'} 133 | cpu: [x64] 134 | os: [android] 135 | 136 | '@esbuild/darwin-arm64@0.24.2': 137 | resolution: {integrity: sha512-kj3AnYWc+CekmZnS5IPu9D+HWtUI49hbnyqk0FLEJDbzCIQt7hg7ucF1SQAilhtYpIujfaHr6O0UHlzzSPdOeA==} 138 | engines: {node: '>=18'} 139 | cpu: [arm64] 140 | os: [darwin] 141 | 142 | '@esbuild/darwin-x64@0.24.2': 143 | resolution: {integrity: sha512-WeSrmwwHaPkNR5H3yYfowhZcbriGqooyu3zI/3GGpF8AyUdsrrP0X6KumITGA9WOyiJavnGZUwPGvxvwfWPHIA==} 144 | engines: {node: '>=18'} 145 | cpu: [x64] 146 | os: [darwin] 147 | 148 | '@esbuild/freebsd-arm64@0.24.2': 149 | resolution: {integrity: sha512-UN8HXjtJ0k/Mj6a9+5u6+2eZ2ERD7Edt1Q9IZiB5UZAIdPnVKDoG7mdTVGhHJIeEml60JteamR3qhsr1r8gXvg==} 150 | engines: {node: '>=18'} 151 | cpu: [arm64] 152 | os: [freebsd] 153 | 154 | '@esbuild/freebsd-x64@0.24.2': 155 | resolution: {integrity: sha512-TvW7wE/89PYW+IevEJXZ5sF6gJRDY/14hyIGFXdIucxCsbRmLUcjseQu1SyTko+2idmCw94TgyaEZi9HUSOe3Q==} 156 | engines: {node: '>=18'} 157 | cpu: [x64] 158 | os: [freebsd] 159 | 160 | '@esbuild/linux-arm64@0.24.2': 161 | resolution: {integrity: sha512-7HnAD6074BW43YvvUmE/35Id9/NB7BeX5EoNkK9obndmZBUk8xmJJeU7DwmUeN7tkysslb2eSl6CTrYz6oEMQg==} 162 | engines: {node: '>=18'} 163 | cpu: [arm64] 164 | os: [linux] 165 | 166 | '@esbuild/linux-arm@0.24.2': 167 | resolution: {integrity: sha512-n0WRM/gWIdU29J57hJyUdIsk0WarGd6To0s+Y+LwvlC55wt+GT/OgkwoXCXvIue1i1sSNWblHEig00GBWiJgfA==} 168 | engines: {node: '>=18'} 169 | cpu: [arm] 170 | os: [linux] 171 | 172 | '@esbuild/linux-ia32@0.24.2': 173 | resolution: {integrity: sha512-sfv0tGPQhcZOgTKO3oBE9xpHuUqguHvSo4jl+wjnKwFpapx+vUDcawbwPNuBIAYdRAvIDBfZVvXprIj3HA+Ugw==} 174 | engines: {node: '>=18'} 175 | cpu: [ia32] 176 | os: [linux] 177 | 178 | '@esbuild/linux-loong64@0.24.2': 179 | resolution: {integrity: sha512-CN9AZr8kEndGooS35ntToZLTQLHEjtVB5n7dl8ZcTZMonJ7CCfStrYhrzF97eAecqVbVJ7APOEe18RPI4KLhwQ==} 180 | engines: {node: '>=18'} 181 | cpu: [loong64] 182 | os: [linux] 183 | 184 | '@esbuild/linux-mips64el@0.24.2': 185 | resolution: {integrity: sha512-iMkk7qr/wl3exJATwkISxI7kTcmHKE+BlymIAbHO8xanq/TjHaaVThFF6ipWzPHryoFsesNQJPE/3wFJw4+huw==} 186 | engines: {node: '>=18'} 187 | cpu: [mips64el] 188 | os: [linux] 189 | 190 | '@esbuild/linux-ppc64@0.24.2': 191 | resolution: {integrity: sha512-shsVrgCZ57Vr2L8mm39kO5PPIb+843FStGt7sGGoqiiWYconSxwTiuswC1VJZLCjNiMLAMh34jg4VSEQb+iEbw==} 192 | engines: {node: '>=18'} 193 | cpu: [ppc64] 194 | os: [linux] 195 | 196 | '@esbuild/linux-riscv64@0.24.2': 197 | resolution: {integrity: sha512-4eSFWnU9Hhd68fW16GD0TINewo1L6dRrB+oLNNbYyMUAeOD2yCK5KXGK1GH4qD/kT+bTEXjsyTCiJGHPZ3eM9Q==} 198 | engines: {node: '>=18'} 199 | cpu: [riscv64] 200 | os: [linux] 201 | 202 | '@esbuild/linux-s390x@0.24.2': 203 | resolution: {integrity: sha512-S0Bh0A53b0YHL2XEXC20bHLuGMOhFDO6GN4b3YjRLK//Ep3ql3erpNcPlEFed93hsQAjAQDNsvcK+hV90FubSw==} 204 | engines: {node: '>=18'} 205 | cpu: [s390x] 206 | os: [linux] 207 | 208 | '@esbuild/linux-x64@0.24.2': 209 | resolution: {integrity: sha512-8Qi4nQcCTbLnK9WoMjdC9NiTG6/E38RNICU6sUNqK0QFxCYgoARqVqxdFmWkdonVsvGqWhmm7MO0jyTqLqwj0Q==} 210 | engines: {node: '>=18'} 211 | cpu: [x64] 212 | os: [linux] 213 | 214 | '@esbuild/netbsd-arm64@0.24.2': 215 | resolution: {integrity: sha512-wuLK/VztRRpMt9zyHSazyCVdCXlpHkKm34WUyinD2lzK07FAHTq0KQvZZlXikNWkDGoT6x3TD51jKQ7gMVpopw==} 216 | engines: {node: '>=18'} 217 | cpu: [arm64] 218 | os: [netbsd] 219 | 220 | '@esbuild/netbsd-x64@0.24.2': 221 | resolution: {integrity: sha512-VefFaQUc4FMmJuAxmIHgUmfNiLXY438XrL4GDNV1Y1H/RW3qow68xTwjZKfj/+Plp9NANmzbH5R40Meudu8mmw==} 222 | engines: {node: '>=18'} 223 | cpu: [x64] 224 | os: [netbsd] 225 | 226 | '@esbuild/openbsd-arm64@0.24.2': 227 | resolution: {integrity: sha512-YQbi46SBct6iKnszhSvdluqDmxCJA+Pu280Av9WICNwQmMxV7nLRHZfjQzwbPs3jeWnuAhE9Jy0NrnJ12Oz+0A==} 228 | engines: {node: '>=18'} 229 | cpu: [arm64] 230 | os: [openbsd] 231 | 232 | '@esbuild/openbsd-x64@0.24.2': 233 | resolution: {integrity: sha512-+iDS6zpNM6EnJyWv0bMGLWSWeXGN/HTaF/LXHXHwejGsVi+ooqDfMCCTerNFxEkM3wYVcExkeGXNqshc9iMaOA==} 234 | engines: {node: '>=18'} 235 | cpu: [x64] 236 | os: [openbsd] 237 | 238 | '@esbuild/sunos-x64@0.24.2': 239 | resolution: {integrity: sha512-hTdsW27jcktEvpwNHJU4ZwWFGkz2zRJUz8pvddmXPtXDzVKTTINmlmga3ZzwcuMpUvLw7JkLy9QLKyGpD2Yxig==} 240 | engines: {node: '>=18'} 241 | cpu: [x64] 242 | os: [sunos] 243 | 244 | '@esbuild/win32-arm64@0.24.2': 245 | resolution: {integrity: sha512-LihEQ2BBKVFLOC9ZItT9iFprsE9tqjDjnbulhHoFxYQtQfai7qfluVODIYxt1PgdoyQkz23+01rzwNwYfutxUQ==} 246 | engines: {node: '>=18'} 247 | cpu: [arm64] 248 | os: [win32] 249 | 250 | '@esbuild/win32-ia32@0.24.2': 251 | resolution: {integrity: sha512-q+iGUwfs8tncmFC9pcnD5IvRHAzmbwQ3GPS5/ceCyHdjXubwQWI12MKWSNSMYLJMq23/IUCvJMS76PDqXe1fxA==} 252 | engines: {node: '>=18'} 253 | cpu: [ia32] 254 | os: [win32] 255 | 256 | '@esbuild/win32-x64@0.24.2': 257 | resolution: {integrity: sha512-7VTgWzgMGvup6aSqDPLiW5zHaxYJGTO4OokMjIlrCtf+VpEL+cXKtCvg723iguPYI5oaUNdS+/V7OU2gvXVWEg==} 258 | engines: {node: '>=18'} 259 | cpu: [x64] 260 | os: [win32] 261 | 262 | '@isaacs/cliui@8.0.2': 263 | resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} 264 | engines: {node: '>=12'} 265 | 266 | '@jridgewell/gen-mapping@0.3.8': 267 | resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} 268 | engines: {node: '>=6.0.0'} 269 | 270 | '@jridgewell/resolve-uri@3.1.2': 271 | resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} 272 | engines: {node: '>=6.0.0'} 273 | 274 | '@jridgewell/set-array@1.2.1': 275 | resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} 276 | engines: {node: '>=6.0.0'} 277 | 278 | '@jridgewell/source-map@0.3.6': 279 | resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} 280 | 281 | '@jridgewell/sourcemap-codec@1.5.0': 282 | resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} 283 | 284 | '@jridgewell/trace-mapping@0.3.25': 285 | resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} 286 | 287 | '@manypkg/find-root@1.1.0': 288 | resolution: {integrity: sha512-mki5uBvhHzO8kYYix/WRy2WX8S3B5wdVSc9D6KcU5lQNglP2yt58/VfLuAK49glRXChosY8ap2oJ1qgma3GUVA==} 289 | 290 | '@manypkg/get-packages@1.1.3': 291 | resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} 292 | 293 | '@nodelib/fs.scandir@2.1.5': 294 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 295 | engines: {node: '>= 8'} 296 | 297 | '@nodelib/fs.stat@2.0.5': 298 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 299 | engines: {node: '>= 8'} 300 | 301 | '@nodelib/fs.walk@1.2.8': 302 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 303 | engines: {node: '>= 8'} 304 | 305 | '@pkgjs/parseargs@0.11.0': 306 | resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} 307 | engines: {node: '>=14'} 308 | 309 | '@rollup/plugin-commonjs@28.0.2': 310 | resolution: {integrity: sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==} 311 | engines: {node: '>=16.0.0 || 14 >= 14.17'} 312 | peerDependencies: 313 | rollup: ^2.68.0||^3.0.0||^4.0.0 314 | peerDependenciesMeta: 315 | rollup: 316 | optional: true 317 | 318 | '@rollup/plugin-node-resolve@16.0.0': 319 | resolution: {integrity: sha512-0FPvAeVUT/zdWoO0jnb/V5BlBsUSNfkIOtFHzMO4H9MOklrmQFY6FduVHKucNb/aTFxvnGhj4MNj/T1oNdDfNg==} 320 | engines: {node: '>=14.0.0'} 321 | peerDependencies: 322 | rollup: ^2.78.0||^3.0.0||^4.0.0 323 | peerDependenciesMeta: 324 | rollup: 325 | optional: true 326 | 327 | '@rollup/plugin-terser@0.4.4': 328 | resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} 329 | engines: {node: '>=14.0.0'} 330 | peerDependencies: 331 | rollup: ^2.0.0||^3.0.0||^4.0.0 332 | peerDependenciesMeta: 333 | rollup: 334 | optional: true 335 | 336 | '@rollup/plugin-typescript@12.1.2': 337 | resolution: {integrity: sha512-cdtSp154H5sv637uMr1a8OTWB0L1SWDSm1rDGiyfcGcvQ6cuTs4MDk2BVEBGysUWago4OJN4EQZqOTl/QY3Jgg==} 338 | engines: {node: '>=14.0.0'} 339 | peerDependencies: 340 | rollup: ^2.14.0||^3.0.0||^4.0.0 341 | tslib: '*' 342 | typescript: '>=3.7.0' 343 | peerDependenciesMeta: 344 | rollup: 345 | optional: true 346 | tslib: 347 | optional: true 348 | 349 | '@rollup/pluginutils@5.1.4': 350 | resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} 351 | engines: {node: '>=14.0.0'} 352 | peerDependencies: 353 | rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 354 | peerDependenciesMeta: 355 | rollup: 356 | optional: true 357 | 358 | '@rollup/rollup-android-arm-eabi@4.34.8': 359 | resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==} 360 | cpu: [arm] 361 | os: [android] 362 | 363 | '@rollup/rollup-android-arm64@4.34.8': 364 | resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==} 365 | cpu: [arm64] 366 | os: [android] 367 | 368 | '@rollup/rollup-darwin-arm64@4.34.8': 369 | resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==} 370 | cpu: [arm64] 371 | os: [darwin] 372 | 373 | '@rollup/rollup-darwin-x64@4.34.8': 374 | resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==} 375 | cpu: [x64] 376 | os: [darwin] 377 | 378 | '@rollup/rollup-freebsd-arm64@4.34.8': 379 | resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==} 380 | cpu: [arm64] 381 | os: [freebsd] 382 | 383 | '@rollup/rollup-freebsd-x64@4.34.8': 384 | resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==} 385 | cpu: [x64] 386 | os: [freebsd] 387 | 388 | '@rollup/rollup-linux-arm-gnueabihf@4.34.8': 389 | resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==} 390 | cpu: [arm] 391 | os: [linux] 392 | 393 | '@rollup/rollup-linux-arm-musleabihf@4.34.8': 394 | resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==} 395 | cpu: [arm] 396 | os: [linux] 397 | 398 | '@rollup/rollup-linux-arm64-gnu@4.34.8': 399 | resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==} 400 | cpu: [arm64] 401 | os: [linux] 402 | 403 | '@rollup/rollup-linux-arm64-musl@4.34.8': 404 | resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==} 405 | cpu: [arm64] 406 | os: [linux] 407 | 408 | '@rollup/rollup-linux-loongarch64-gnu@4.34.8': 409 | resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==} 410 | cpu: [loong64] 411 | os: [linux] 412 | 413 | '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': 414 | resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==} 415 | cpu: [ppc64] 416 | os: [linux] 417 | 418 | '@rollup/rollup-linux-riscv64-gnu@4.34.8': 419 | resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==} 420 | cpu: [riscv64] 421 | os: [linux] 422 | 423 | '@rollup/rollup-linux-s390x-gnu@4.34.8': 424 | resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==} 425 | cpu: [s390x] 426 | os: [linux] 427 | 428 | '@rollup/rollup-linux-x64-gnu@4.34.8': 429 | resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==} 430 | cpu: [x64] 431 | os: [linux] 432 | 433 | '@rollup/rollup-linux-x64-musl@4.34.8': 434 | resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==} 435 | cpu: [x64] 436 | os: [linux] 437 | 438 | '@rollup/rollup-win32-arm64-msvc@4.34.8': 439 | resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==} 440 | cpu: [arm64] 441 | os: [win32] 442 | 443 | '@rollup/rollup-win32-ia32-msvc@4.34.8': 444 | resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==} 445 | cpu: [ia32] 446 | os: [win32] 447 | 448 | '@rollup/rollup-win32-x64-msvc@4.34.8': 449 | resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==} 450 | cpu: [x64] 451 | os: [win32] 452 | 453 | '@types/estree@1.0.6': 454 | resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} 455 | 456 | '@types/node@12.20.55': 457 | resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} 458 | 459 | '@types/node@22.13.5': 460 | resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==} 461 | 462 | '@types/resolve@1.20.2': 463 | resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} 464 | 465 | acorn@8.14.0: 466 | resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} 467 | engines: {node: '>=0.4.0'} 468 | hasBin: true 469 | 470 | ansi-colors@4.1.3: 471 | resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} 472 | engines: {node: '>=6'} 473 | 474 | ansi-regex@5.0.1: 475 | resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} 476 | engines: {node: '>=8'} 477 | 478 | ansi-regex@6.1.0: 479 | resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} 480 | engines: {node: '>=12'} 481 | 482 | ansi-styles@4.3.0: 483 | resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} 484 | engines: {node: '>=8'} 485 | 486 | ansi-styles@6.2.1: 487 | resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} 488 | engines: {node: '>=12'} 489 | 490 | any-promise@1.3.0: 491 | resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} 492 | 493 | argparse@1.0.10: 494 | resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} 495 | 496 | array-union@2.1.0: 497 | resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} 498 | engines: {node: '>=8'} 499 | 500 | ass-compiler@0.1.15: 501 | resolution: {integrity: sha512-NPbNjCawqK/MKt1+0v5xezVxV2qk4AKIdl6tM3BsUohWQFb46WJaC0wJzMXlyGZbBJxx/AqKj3nalMSl+JZ+Jw==} 502 | 503 | balanced-match@1.0.2: 504 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 505 | 506 | better-path-resolve@1.0.0: 507 | resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} 508 | engines: {node: '>=4'} 509 | 510 | brace-expansion@2.0.1: 511 | resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} 512 | 513 | braces@3.0.3: 514 | resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} 515 | engines: {node: '>=8'} 516 | 517 | buffer-from@1.1.2: 518 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 519 | 520 | bundle-require@5.1.0: 521 | resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} 522 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 523 | peerDependencies: 524 | esbuild: '>=0.18' 525 | 526 | cac@6.7.14: 527 | resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} 528 | engines: {node: '>=8'} 529 | 530 | chardet@0.7.0: 531 | resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} 532 | 533 | chokidar@4.0.3: 534 | resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} 535 | engines: {node: '>= 14.16.0'} 536 | 537 | ci-info@3.9.0: 538 | resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} 539 | engines: {node: '>=8'} 540 | 541 | color-convert@2.0.1: 542 | resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} 543 | engines: {node: '>=7.0.0'} 544 | 545 | color-name@1.1.4: 546 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 547 | 548 | commander@2.20.3: 549 | resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} 550 | 551 | commander@4.1.1: 552 | resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} 553 | engines: {node: '>= 6'} 554 | 555 | commondir@1.0.1: 556 | resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} 557 | 558 | consola@3.4.0: 559 | resolution: {integrity: sha512-EiPU8G6dQG0GFHNR8ljnZFki/8a+cQwEQ+7wpxdChl02Q8HXlwEZWD5lqAF8vC2sEC3Tehr8hy7vErz88LHyUA==} 560 | engines: {node: ^14.18.0 || >=16.10.0} 561 | 562 | cross-spawn@7.0.6: 563 | resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} 564 | engines: {node: '>= 8'} 565 | 566 | debug@4.4.0: 567 | resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} 568 | engines: {node: '>=6.0'} 569 | peerDependencies: 570 | supports-color: '*' 571 | peerDependenciesMeta: 572 | supports-color: 573 | optional: true 574 | 575 | deepmerge@4.3.1: 576 | resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} 577 | engines: {node: '>=0.10.0'} 578 | 579 | detect-indent@6.1.0: 580 | resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} 581 | engines: {node: '>=8'} 582 | 583 | dir-glob@3.0.1: 584 | resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} 585 | engines: {node: '>=8'} 586 | 587 | eastasianwidth@0.2.0: 588 | resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} 589 | 590 | emoji-regex@8.0.0: 591 | resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} 592 | 593 | emoji-regex@9.2.2: 594 | resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} 595 | 596 | enquirer@2.4.1: 597 | resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} 598 | engines: {node: '>=8.6'} 599 | 600 | esbuild@0.24.2: 601 | resolution: {integrity: sha512-+9egpBW8I3CD5XPe0n6BfT5fxLzxrlDzqydF3aviG+9ni1lDC/OvMHcxqEFV0+LANZG5R1bFMWfUrjVsdwxJvA==} 602 | engines: {node: '>=18'} 603 | hasBin: true 604 | 605 | esprima@4.0.1: 606 | resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} 607 | engines: {node: '>=4'} 608 | hasBin: true 609 | 610 | estree-walker@2.0.2: 611 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 612 | 613 | extendable-error@0.1.7: 614 | resolution: {integrity: sha512-UOiS2in6/Q0FK0R0q6UY9vYpQ21mr/Qn1KOnte7vsACuNJf514WvCCUHSRCPcgjPT2bAhNIJdlE6bVap1GKmeg==} 615 | 616 | external-editor@3.1.0: 617 | resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} 618 | engines: {node: '>=4'} 619 | 620 | fast-glob@3.3.3: 621 | resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} 622 | engines: {node: '>=8.6.0'} 623 | 624 | fastq@1.19.0: 625 | resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==} 626 | 627 | fdir@6.4.3: 628 | resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} 629 | peerDependencies: 630 | picomatch: ^3 || ^4 631 | peerDependenciesMeta: 632 | picomatch: 633 | optional: true 634 | 635 | fill-range@7.1.1: 636 | resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} 637 | engines: {node: '>=8'} 638 | 639 | find-up@4.1.0: 640 | resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} 641 | engines: {node: '>=8'} 642 | 643 | foreground-child@3.3.0: 644 | resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} 645 | engines: {node: '>=14'} 646 | 647 | fs-extra@7.0.1: 648 | resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} 649 | engines: {node: '>=6 <7 || >=8'} 650 | 651 | fs-extra@8.1.0: 652 | resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} 653 | engines: {node: '>=6 <7 || >=8'} 654 | 655 | fsevents@2.3.3: 656 | resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} 657 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 658 | os: [darwin] 659 | 660 | function-bind@1.1.2: 661 | resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} 662 | 663 | glob-parent@5.1.2: 664 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 665 | engines: {node: '>= 6'} 666 | 667 | glob@10.4.5: 668 | resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} 669 | hasBin: true 670 | 671 | globby@11.1.0: 672 | resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} 673 | engines: {node: '>=10'} 674 | 675 | graceful-fs@4.2.11: 676 | resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} 677 | 678 | hasown@2.0.2: 679 | resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} 680 | engines: {node: '>= 0.4'} 681 | 682 | human-id@4.1.1: 683 | resolution: {integrity: sha512-3gKm/gCSUipeLsRYZbbdA1BD83lBoWUkZ7G9VFrhWPAU76KwYo5KR8V28bpoPm/ygy0x5/GCbpRQdY7VLYCoIg==} 684 | hasBin: true 685 | 686 | iconv-lite@0.4.24: 687 | resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} 688 | engines: {node: '>=0.10.0'} 689 | 690 | ignore@5.3.2: 691 | resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} 692 | engines: {node: '>= 4'} 693 | 694 | is-core-module@2.16.1: 695 | resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} 696 | engines: {node: '>= 0.4'} 697 | 698 | is-extglob@2.1.1: 699 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 700 | engines: {node: '>=0.10.0'} 701 | 702 | is-fullwidth-code-point@3.0.0: 703 | resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} 704 | engines: {node: '>=8'} 705 | 706 | is-glob@4.0.3: 707 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 708 | engines: {node: '>=0.10.0'} 709 | 710 | is-module@1.0.0: 711 | resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} 712 | 713 | is-number@7.0.0: 714 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 715 | engines: {node: '>=0.12.0'} 716 | 717 | is-reference@1.2.1: 718 | resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} 719 | 720 | is-subdir@1.2.0: 721 | resolution: {integrity: sha512-2AT6j+gXe/1ueqbW6fLZJiIw3F8iXGJtt0yDrZaBhAZEG1raiTxKWU+IPqMCzQAXOUCKdA4UDMgacKH25XG2Cw==} 722 | engines: {node: '>=4'} 723 | 724 | is-windows@1.0.2: 725 | resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} 726 | engines: {node: '>=0.10.0'} 727 | 728 | isexe@2.0.0: 729 | resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} 730 | 731 | jackspeak@3.4.3: 732 | resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} 733 | 734 | joycon@3.1.1: 735 | resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} 736 | engines: {node: '>=10'} 737 | 738 | js-yaml@3.14.1: 739 | resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} 740 | hasBin: true 741 | 742 | jsonfile@4.0.0: 743 | resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} 744 | 745 | lilconfig@3.1.3: 746 | resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} 747 | engines: {node: '>=14'} 748 | 749 | lines-and-columns@1.2.4: 750 | resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} 751 | 752 | load-tsconfig@0.2.5: 753 | resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} 754 | engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} 755 | 756 | locate-path@5.0.0: 757 | resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} 758 | engines: {node: '>=8'} 759 | 760 | lodash.sortby@4.7.0: 761 | resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} 762 | 763 | lodash.startcase@4.4.0: 764 | resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} 765 | 766 | lru-cache@10.4.3: 767 | resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} 768 | 769 | magic-string@0.30.17: 770 | resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} 771 | 772 | merge2@1.4.1: 773 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 774 | engines: {node: '>= 8'} 775 | 776 | micromatch@4.0.8: 777 | resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} 778 | engines: {node: '>=8.6'} 779 | 780 | minimatch@9.0.5: 781 | resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} 782 | engines: {node: '>=16 || 14 >=14.17'} 783 | 784 | minipass@7.1.2: 785 | resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} 786 | engines: {node: '>=16 || 14 >=14.17'} 787 | 788 | mri@1.2.0: 789 | resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} 790 | engines: {node: '>=4'} 791 | 792 | ms@2.1.3: 793 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 794 | 795 | mz@2.7.0: 796 | resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} 797 | 798 | object-assign@4.1.1: 799 | resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} 800 | engines: {node: '>=0.10.0'} 801 | 802 | os-tmpdir@1.0.2: 803 | resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} 804 | engines: {node: '>=0.10.0'} 805 | 806 | outdent@0.5.0: 807 | resolution: {integrity: sha512-/jHxFIzoMXdqPzTaCpFzAAWhpkSjZPF4Vsn6jAfNpmbH/ymsmd7Qc6VE9BGn0L6YMj6uwpQLxCECpus4ukKS9Q==} 808 | 809 | p-filter@2.1.0: 810 | resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} 811 | engines: {node: '>=8'} 812 | 813 | p-limit@2.3.0: 814 | resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} 815 | engines: {node: '>=6'} 816 | 817 | p-locate@4.1.0: 818 | resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} 819 | engines: {node: '>=8'} 820 | 821 | p-map@2.1.0: 822 | resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} 823 | engines: {node: '>=6'} 824 | 825 | p-try@2.2.0: 826 | resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} 827 | engines: {node: '>=6'} 828 | 829 | package-json-from-dist@1.0.1: 830 | resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} 831 | 832 | package-manager-detector@0.2.9: 833 | resolution: {integrity: sha512-+vYvA/Y31l8Zk8dwxHhL3JfTuHPm6tlxM2A3GeQyl7ovYnSp1+mzAxClxaOr0qO1TtPxbQxetI7v5XqKLJZk7Q==} 834 | 835 | path-exists@4.0.0: 836 | resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} 837 | engines: {node: '>=8'} 838 | 839 | path-key@3.1.1: 840 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 841 | engines: {node: '>=8'} 842 | 843 | path-parse@1.0.7: 844 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 845 | 846 | path-scurry@1.11.1: 847 | resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} 848 | engines: {node: '>=16 || 14 >=14.18'} 849 | 850 | path-type@4.0.0: 851 | resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} 852 | engines: {node: '>=8'} 853 | 854 | picocolors@1.1.1: 855 | resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} 856 | 857 | picomatch@2.3.1: 858 | resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} 859 | engines: {node: '>=8.6'} 860 | 861 | picomatch@4.0.2: 862 | resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} 863 | engines: {node: '>=12'} 864 | 865 | pify@4.0.1: 866 | resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} 867 | engines: {node: '>=6'} 868 | 869 | pirates@4.0.6: 870 | resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} 871 | engines: {node: '>= 6'} 872 | 873 | postcss-load-config@6.0.1: 874 | resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} 875 | engines: {node: '>= 18'} 876 | peerDependencies: 877 | jiti: '>=1.21.0' 878 | postcss: '>=8.0.9' 879 | tsx: ^4.8.1 880 | yaml: ^2.4.2 881 | peerDependenciesMeta: 882 | jiti: 883 | optional: true 884 | postcss: 885 | optional: true 886 | tsx: 887 | optional: true 888 | yaml: 889 | optional: true 890 | 891 | prettier@2.8.8: 892 | resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} 893 | engines: {node: '>=10.13.0'} 894 | hasBin: true 895 | 896 | prettier@3.5.2: 897 | resolution: {integrity: sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==} 898 | engines: {node: '>=14'} 899 | hasBin: true 900 | 901 | punycode@2.3.1: 902 | resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} 903 | engines: {node: '>=6'} 904 | 905 | queue-microtask@1.2.3: 906 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 907 | 908 | randombytes@2.1.0: 909 | resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} 910 | 911 | read-yaml-file@1.1.0: 912 | resolution: {integrity: sha512-VIMnQi/Z4HT2Fxuwg5KrY174U1VdUIASQVWXXyqtNRtxSr9IYkn1rsI6Tb6HsrHCmB7gVpNwX6JxPTHcH6IoTA==} 913 | engines: {node: '>=6'} 914 | 915 | readdirp@4.1.1: 916 | resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} 917 | engines: {node: '>= 14.18.0'} 918 | 919 | regenerator-runtime@0.14.1: 920 | resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} 921 | 922 | resolve-from@5.0.0: 923 | resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} 924 | engines: {node: '>=8'} 925 | 926 | resolve@1.22.10: 927 | resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} 928 | engines: {node: '>= 0.4'} 929 | hasBin: true 930 | 931 | reusify@1.0.4: 932 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 933 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 934 | 935 | rollup@4.34.8: 936 | resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==} 937 | engines: {node: '>=18.0.0', npm: '>=8.0.0'} 938 | hasBin: true 939 | 940 | run-parallel@1.2.0: 941 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 942 | 943 | safe-buffer@5.2.1: 944 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 945 | 946 | safer-buffer@2.1.2: 947 | resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} 948 | 949 | semver@7.7.1: 950 | resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} 951 | engines: {node: '>=10'} 952 | hasBin: true 953 | 954 | serialize-javascript@6.0.2: 955 | resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} 956 | 957 | shebang-command@2.0.0: 958 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 959 | engines: {node: '>=8'} 960 | 961 | shebang-regex@3.0.0: 962 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 963 | engines: {node: '>=8'} 964 | 965 | signal-exit@4.1.0: 966 | resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} 967 | engines: {node: '>=14'} 968 | 969 | slash@3.0.0: 970 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 971 | engines: {node: '>=8'} 972 | 973 | smob@1.5.0: 974 | resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} 975 | 976 | source-map-support@0.5.21: 977 | resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} 978 | 979 | source-map@0.6.1: 980 | resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} 981 | engines: {node: '>=0.10.0'} 982 | 983 | source-map@0.8.0-beta.0: 984 | resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} 985 | engines: {node: '>= 8'} 986 | 987 | spawndamnit@3.0.1: 988 | resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} 989 | 990 | sprintf-js@1.0.3: 991 | resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} 992 | 993 | string-width@4.2.3: 994 | resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} 995 | engines: {node: '>=8'} 996 | 997 | string-width@5.1.2: 998 | resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} 999 | engines: {node: '>=12'} 1000 | 1001 | strip-ansi@6.0.1: 1002 | resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} 1003 | engines: {node: '>=8'} 1004 | 1005 | strip-ansi@7.1.0: 1006 | resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} 1007 | engines: {node: '>=12'} 1008 | 1009 | strip-bom@3.0.0: 1010 | resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} 1011 | engines: {node: '>=4'} 1012 | 1013 | sucrase@3.35.0: 1014 | resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} 1015 | engines: {node: '>=16 || 14 >=14.17'} 1016 | hasBin: true 1017 | 1018 | supports-preserve-symlinks-flag@1.0.0: 1019 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1020 | engines: {node: '>= 0.4'} 1021 | 1022 | term-size@2.2.1: 1023 | resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} 1024 | engines: {node: '>=8'} 1025 | 1026 | terser@5.39.0: 1027 | resolution: {integrity: sha512-LBAhFyLho16harJoWMg/nZsQYgTrg5jXOn2nCYjRUcZZEdE3qa2zb8QEDRUGVZBW4rlazf2fxkg8tztybTaqWw==} 1028 | engines: {node: '>=10'} 1029 | hasBin: true 1030 | 1031 | thenify-all@1.6.0: 1032 | resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} 1033 | engines: {node: '>=0.8'} 1034 | 1035 | thenify@3.3.1: 1036 | resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} 1037 | 1038 | tinyexec@0.3.2: 1039 | resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} 1040 | 1041 | tinyglobby@0.2.10: 1042 | resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} 1043 | engines: {node: '>=12.0.0'} 1044 | 1045 | tmp@0.0.33: 1046 | resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} 1047 | engines: {node: '>=0.6.0'} 1048 | 1049 | to-regex-range@5.0.1: 1050 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1051 | engines: {node: '>=8.0'} 1052 | 1053 | tr46@1.0.1: 1054 | resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} 1055 | 1056 | tree-kill@1.2.2: 1057 | resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} 1058 | hasBin: true 1059 | 1060 | ts-interface-checker@0.1.13: 1061 | resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} 1062 | 1063 | tslib@2.8.1: 1064 | resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} 1065 | 1066 | tsup@8.3.6: 1067 | resolution: {integrity: sha512-XkVtlDV/58S9Ye0JxUUTcrQk4S+EqlOHKzg6Roa62rdjL1nGWNUstG0xgI4vanHdfIpjP448J8vlN0oK6XOJ5g==} 1068 | engines: {node: '>=18'} 1069 | hasBin: true 1070 | peerDependencies: 1071 | '@microsoft/api-extractor': ^7.36.0 1072 | '@swc/core': ^1 1073 | postcss: ^8.4.12 1074 | typescript: '>=4.5.0' 1075 | peerDependenciesMeta: 1076 | '@microsoft/api-extractor': 1077 | optional: true 1078 | '@swc/core': 1079 | optional: true 1080 | postcss: 1081 | optional: true 1082 | typescript: 1083 | optional: true 1084 | 1085 | typescript@5.7.3: 1086 | resolution: {integrity: sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==} 1087 | engines: {node: '>=14.17'} 1088 | hasBin: true 1089 | 1090 | undici-types@6.20.0: 1091 | resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} 1092 | 1093 | universalify@0.1.2: 1094 | resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} 1095 | engines: {node: '>= 4.0.0'} 1096 | 1097 | webidl-conversions@4.0.2: 1098 | resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} 1099 | 1100 | whatwg-url@7.1.0: 1101 | resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} 1102 | 1103 | which@2.0.2: 1104 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1105 | engines: {node: '>= 8'} 1106 | hasBin: true 1107 | 1108 | wrap-ansi@7.0.0: 1109 | resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} 1110 | engines: {node: '>=10'} 1111 | 1112 | wrap-ansi@8.1.0: 1113 | resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} 1114 | engines: {node: '>=12'} 1115 | 1116 | yaml@2.4.2: 1117 | resolution: {integrity: sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==} 1118 | engines: {node: '>= 14'} 1119 | hasBin: true 1120 | 1121 | snapshots: 1122 | 1123 | '@babel/runtime@7.26.9': 1124 | dependencies: 1125 | regenerator-runtime: 0.14.1 1126 | 1127 | '@changesets/apply-release-plan@7.0.10': 1128 | dependencies: 1129 | '@changesets/config': 3.1.1 1130 | '@changesets/get-version-range-type': 0.4.0 1131 | '@changesets/git': 3.0.2 1132 | '@changesets/should-skip-package': 0.1.2 1133 | '@changesets/types': 6.1.0 1134 | '@manypkg/get-packages': 1.1.3 1135 | detect-indent: 6.1.0 1136 | fs-extra: 7.0.1 1137 | lodash.startcase: 4.4.0 1138 | outdent: 0.5.0 1139 | prettier: 2.8.8 1140 | resolve-from: 5.0.0 1141 | semver: 7.7.1 1142 | 1143 | '@changesets/assemble-release-plan@6.0.6': 1144 | dependencies: 1145 | '@changesets/errors': 0.2.0 1146 | '@changesets/get-dependents-graph': 2.1.3 1147 | '@changesets/should-skip-package': 0.1.2 1148 | '@changesets/types': 6.1.0 1149 | '@manypkg/get-packages': 1.1.3 1150 | semver: 7.7.1 1151 | 1152 | '@changesets/changelog-git@0.2.1': 1153 | dependencies: 1154 | '@changesets/types': 6.1.0 1155 | 1156 | '@changesets/cli@2.28.1': 1157 | dependencies: 1158 | '@changesets/apply-release-plan': 7.0.10 1159 | '@changesets/assemble-release-plan': 6.0.6 1160 | '@changesets/changelog-git': 0.2.1 1161 | '@changesets/config': 3.1.1 1162 | '@changesets/errors': 0.2.0 1163 | '@changesets/get-dependents-graph': 2.1.3 1164 | '@changesets/get-release-plan': 4.0.8 1165 | '@changesets/git': 3.0.2 1166 | '@changesets/logger': 0.1.1 1167 | '@changesets/pre': 2.0.2 1168 | '@changesets/read': 0.6.3 1169 | '@changesets/should-skip-package': 0.1.2 1170 | '@changesets/types': 6.1.0 1171 | '@changesets/write': 0.4.0 1172 | '@manypkg/get-packages': 1.1.3 1173 | ansi-colors: 4.1.3 1174 | ci-info: 3.9.0 1175 | enquirer: 2.4.1 1176 | external-editor: 3.1.0 1177 | fs-extra: 7.0.1 1178 | mri: 1.2.0 1179 | p-limit: 2.3.0 1180 | package-manager-detector: 0.2.9 1181 | picocolors: 1.1.1 1182 | resolve-from: 5.0.0 1183 | semver: 7.7.1 1184 | spawndamnit: 3.0.1 1185 | term-size: 2.2.1 1186 | 1187 | '@changesets/config@3.1.1': 1188 | dependencies: 1189 | '@changesets/errors': 0.2.0 1190 | '@changesets/get-dependents-graph': 2.1.3 1191 | '@changesets/logger': 0.1.1 1192 | '@changesets/types': 6.1.0 1193 | '@manypkg/get-packages': 1.1.3 1194 | fs-extra: 7.0.1 1195 | micromatch: 4.0.8 1196 | 1197 | '@changesets/errors@0.2.0': 1198 | dependencies: 1199 | extendable-error: 0.1.7 1200 | 1201 | '@changesets/get-dependents-graph@2.1.3': 1202 | dependencies: 1203 | '@changesets/types': 6.1.0 1204 | '@manypkg/get-packages': 1.1.3 1205 | picocolors: 1.1.1 1206 | semver: 7.7.1 1207 | 1208 | '@changesets/get-release-plan@4.0.8': 1209 | dependencies: 1210 | '@changesets/assemble-release-plan': 6.0.6 1211 | '@changesets/config': 3.1.1 1212 | '@changesets/pre': 2.0.2 1213 | '@changesets/read': 0.6.3 1214 | '@changesets/types': 6.1.0 1215 | '@manypkg/get-packages': 1.1.3 1216 | 1217 | '@changesets/get-version-range-type@0.4.0': {} 1218 | 1219 | '@changesets/git@3.0.2': 1220 | dependencies: 1221 | '@changesets/errors': 0.2.0 1222 | '@manypkg/get-packages': 1.1.3 1223 | is-subdir: 1.2.0 1224 | micromatch: 4.0.8 1225 | spawndamnit: 3.0.1 1226 | 1227 | '@changesets/logger@0.1.1': 1228 | dependencies: 1229 | picocolors: 1.1.1 1230 | 1231 | '@changesets/parse@0.4.1': 1232 | dependencies: 1233 | '@changesets/types': 6.1.0 1234 | js-yaml: 3.14.1 1235 | 1236 | '@changesets/pre@2.0.2': 1237 | dependencies: 1238 | '@changesets/errors': 0.2.0 1239 | '@changesets/types': 6.1.0 1240 | '@manypkg/get-packages': 1.1.3 1241 | fs-extra: 7.0.1 1242 | 1243 | '@changesets/read@0.6.3': 1244 | dependencies: 1245 | '@changesets/git': 3.0.2 1246 | '@changesets/logger': 0.1.1 1247 | '@changesets/parse': 0.4.1 1248 | '@changesets/types': 6.1.0 1249 | fs-extra: 7.0.1 1250 | p-filter: 2.1.0 1251 | picocolors: 1.1.1 1252 | 1253 | '@changesets/should-skip-package@0.1.2': 1254 | dependencies: 1255 | '@changesets/types': 6.1.0 1256 | '@manypkg/get-packages': 1.1.3 1257 | 1258 | '@changesets/types@4.1.0': {} 1259 | 1260 | '@changesets/types@6.1.0': {} 1261 | 1262 | '@changesets/write@0.4.0': 1263 | dependencies: 1264 | '@changesets/types': 6.1.0 1265 | fs-extra: 7.0.1 1266 | human-id: 4.1.1 1267 | prettier: 2.8.8 1268 | 1269 | '@esbuild/aix-ppc64@0.24.2': 1270 | optional: true 1271 | 1272 | '@esbuild/android-arm64@0.24.2': 1273 | optional: true 1274 | 1275 | '@esbuild/android-arm@0.24.2': 1276 | optional: true 1277 | 1278 | '@esbuild/android-x64@0.24.2': 1279 | optional: true 1280 | 1281 | '@esbuild/darwin-arm64@0.24.2': 1282 | optional: true 1283 | 1284 | '@esbuild/darwin-x64@0.24.2': 1285 | optional: true 1286 | 1287 | '@esbuild/freebsd-arm64@0.24.2': 1288 | optional: true 1289 | 1290 | '@esbuild/freebsd-x64@0.24.2': 1291 | optional: true 1292 | 1293 | '@esbuild/linux-arm64@0.24.2': 1294 | optional: true 1295 | 1296 | '@esbuild/linux-arm@0.24.2': 1297 | optional: true 1298 | 1299 | '@esbuild/linux-ia32@0.24.2': 1300 | optional: true 1301 | 1302 | '@esbuild/linux-loong64@0.24.2': 1303 | optional: true 1304 | 1305 | '@esbuild/linux-mips64el@0.24.2': 1306 | optional: true 1307 | 1308 | '@esbuild/linux-ppc64@0.24.2': 1309 | optional: true 1310 | 1311 | '@esbuild/linux-riscv64@0.24.2': 1312 | optional: true 1313 | 1314 | '@esbuild/linux-s390x@0.24.2': 1315 | optional: true 1316 | 1317 | '@esbuild/linux-x64@0.24.2': 1318 | optional: true 1319 | 1320 | '@esbuild/netbsd-arm64@0.24.2': 1321 | optional: true 1322 | 1323 | '@esbuild/netbsd-x64@0.24.2': 1324 | optional: true 1325 | 1326 | '@esbuild/openbsd-arm64@0.24.2': 1327 | optional: true 1328 | 1329 | '@esbuild/openbsd-x64@0.24.2': 1330 | optional: true 1331 | 1332 | '@esbuild/sunos-x64@0.24.2': 1333 | optional: true 1334 | 1335 | '@esbuild/win32-arm64@0.24.2': 1336 | optional: true 1337 | 1338 | '@esbuild/win32-ia32@0.24.2': 1339 | optional: true 1340 | 1341 | '@esbuild/win32-x64@0.24.2': 1342 | optional: true 1343 | 1344 | '@isaacs/cliui@8.0.2': 1345 | dependencies: 1346 | string-width: 5.1.2 1347 | string-width-cjs: string-width@4.2.3 1348 | strip-ansi: 7.1.0 1349 | strip-ansi-cjs: strip-ansi@6.0.1 1350 | wrap-ansi: 8.1.0 1351 | wrap-ansi-cjs: wrap-ansi@7.0.0 1352 | 1353 | '@jridgewell/gen-mapping@0.3.8': 1354 | dependencies: 1355 | '@jridgewell/set-array': 1.2.1 1356 | '@jridgewell/sourcemap-codec': 1.5.0 1357 | '@jridgewell/trace-mapping': 0.3.25 1358 | 1359 | '@jridgewell/resolve-uri@3.1.2': {} 1360 | 1361 | '@jridgewell/set-array@1.2.1': {} 1362 | 1363 | '@jridgewell/source-map@0.3.6': 1364 | dependencies: 1365 | '@jridgewell/gen-mapping': 0.3.8 1366 | '@jridgewell/trace-mapping': 0.3.25 1367 | 1368 | '@jridgewell/sourcemap-codec@1.5.0': {} 1369 | 1370 | '@jridgewell/trace-mapping@0.3.25': 1371 | dependencies: 1372 | '@jridgewell/resolve-uri': 3.1.2 1373 | '@jridgewell/sourcemap-codec': 1.5.0 1374 | 1375 | '@manypkg/find-root@1.1.0': 1376 | dependencies: 1377 | '@babel/runtime': 7.26.9 1378 | '@types/node': 12.20.55 1379 | find-up: 4.1.0 1380 | fs-extra: 8.1.0 1381 | 1382 | '@manypkg/get-packages@1.1.3': 1383 | dependencies: 1384 | '@babel/runtime': 7.26.9 1385 | '@changesets/types': 4.1.0 1386 | '@manypkg/find-root': 1.1.0 1387 | fs-extra: 8.1.0 1388 | globby: 11.1.0 1389 | read-yaml-file: 1.1.0 1390 | 1391 | '@nodelib/fs.scandir@2.1.5': 1392 | dependencies: 1393 | '@nodelib/fs.stat': 2.0.5 1394 | run-parallel: 1.2.0 1395 | 1396 | '@nodelib/fs.stat@2.0.5': {} 1397 | 1398 | '@nodelib/fs.walk@1.2.8': 1399 | dependencies: 1400 | '@nodelib/fs.scandir': 2.1.5 1401 | fastq: 1.19.0 1402 | 1403 | '@pkgjs/parseargs@0.11.0': 1404 | optional: true 1405 | 1406 | '@rollup/plugin-commonjs@28.0.2(rollup@4.34.8)': 1407 | dependencies: 1408 | '@rollup/pluginutils': 5.1.4(rollup@4.34.8) 1409 | commondir: 1.0.1 1410 | estree-walker: 2.0.2 1411 | fdir: 6.4.3(picomatch@4.0.2) 1412 | is-reference: 1.2.1 1413 | magic-string: 0.30.17 1414 | picomatch: 4.0.2 1415 | optionalDependencies: 1416 | rollup: 4.34.8 1417 | 1418 | '@rollup/plugin-node-resolve@16.0.0(rollup@4.34.8)': 1419 | dependencies: 1420 | '@rollup/pluginutils': 5.1.4(rollup@4.34.8) 1421 | '@types/resolve': 1.20.2 1422 | deepmerge: 4.3.1 1423 | is-module: 1.0.0 1424 | resolve: 1.22.10 1425 | optionalDependencies: 1426 | rollup: 4.34.8 1427 | 1428 | '@rollup/plugin-terser@0.4.4(rollup@4.34.8)': 1429 | dependencies: 1430 | serialize-javascript: 6.0.2 1431 | smob: 1.5.0 1432 | terser: 5.39.0 1433 | optionalDependencies: 1434 | rollup: 4.34.8 1435 | 1436 | '@rollup/plugin-typescript@12.1.2(rollup@4.34.8)(tslib@2.8.1)(typescript@5.7.3)': 1437 | dependencies: 1438 | '@rollup/pluginutils': 5.1.4(rollup@4.34.8) 1439 | resolve: 1.22.10 1440 | typescript: 5.7.3 1441 | optionalDependencies: 1442 | rollup: 4.34.8 1443 | tslib: 2.8.1 1444 | 1445 | '@rollup/pluginutils@5.1.4(rollup@4.34.8)': 1446 | dependencies: 1447 | '@types/estree': 1.0.6 1448 | estree-walker: 2.0.2 1449 | picomatch: 4.0.2 1450 | optionalDependencies: 1451 | rollup: 4.34.8 1452 | 1453 | '@rollup/rollup-android-arm-eabi@4.34.8': 1454 | optional: true 1455 | 1456 | '@rollup/rollup-android-arm64@4.34.8': 1457 | optional: true 1458 | 1459 | '@rollup/rollup-darwin-arm64@4.34.8': 1460 | optional: true 1461 | 1462 | '@rollup/rollup-darwin-x64@4.34.8': 1463 | optional: true 1464 | 1465 | '@rollup/rollup-freebsd-arm64@4.34.8': 1466 | optional: true 1467 | 1468 | '@rollup/rollup-freebsd-x64@4.34.8': 1469 | optional: true 1470 | 1471 | '@rollup/rollup-linux-arm-gnueabihf@4.34.8': 1472 | optional: true 1473 | 1474 | '@rollup/rollup-linux-arm-musleabihf@4.34.8': 1475 | optional: true 1476 | 1477 | '@rollup/rollup-linux-arm64-gnu@4.34.8': 1478 | optional: true 1479 | 1480 | '@rollup/rollup-linux-arm64-musl@4.34.8': 1481 | optional: true 1482 | 1483 | '@rollup/rollup-linux-loongarch64-gnu@4.34.8': 1484 | optional: true 1485 | 1486 | '@rollup/rollup-linux-powerpc64le-gnu@4.34.8': 1487 | optional: true 1488 | 1489 | '@rollup/rollup-linux-riscv64-gnu@4.34.8': 1490 | optional: true 1491 | 1492 | '@rollup/rollup-linux-s390x-gnu@4.34.8': 1493 | optional: true 1494 | 1495 | '@rollup/rollup-linux-x64-gnu@4.34.8': 1496 | optional: true 1497 | 1498 | '@rollup/rollup-linux-x64-musl@4.34.8': 1499 | optional: true 1500 | 1501 | '@rollup/rollup-win32-arm64-msvc@4.34.8': 1502 | optional: true 1503 | 1504 | '@rollup/rollup-win32-ia32-msvc@4.34.8': 1505 | optional: true 1506 | 1507 | '@rollup/rollup-win32-x64-msvc@4.34.8': 1508 | optional: true 1509 | 1510 | '@types/estree@1.0.6': {} 1511 | 1512 | '@types/node@12.20.55': {} 1513 | 1514 | '@types/node@22.13.5': 1515 | dependencies: 1516 | undici-types: 6.20.0 1517 | 1518 | '@types/resolve@1.20.2': {} 1519 | 1520 | acorn@8.14.0: {} 1521 | 1522 | ansi-colors@4.1.3: {} 1523 | 1524 | ansi-regex@5.0.1: {} 1525 | 1526 | ansi-regex@6.1.0: {} 1527 | 1528 | ansi-styles@4.3.0: 1529 | dependencies: 1530 | color-convert: 2.0.1 1531 | 1532 | ansi-styles@6.2.1: {} 1533 | 1534 | any-promise@1.3.0: {} 1535 | 1536 | argparse@1.0.10: 1537 | dependencies: 1538 | sprintf-js: 1.0.3 1539 | 1540 | array-union@2.1.0: {} 1541 | 1542 | ass-compiler@0.1.15: {} 1543 | 1544 | balanced-match@1.0.2: {} 1545 | 1546 | better-path-resolve@1.0.0: 1547 | dependencies: 1548 | is-windows: 1.0.2 1549 | 1550 | brace-expansion@2.0.1: 1551 | dependencies: 1552 | balanced-match: 1.0.2 1553 | 1554 | braces@3.0.3: 1555 | dependencies: 1556 | fill-range: 7.1.1 1557 | 1558 | buffer-from@1.1.2: {} 1559 | 1560 | bundle-require@5.1.0(esbuild@0.24.2): 1561 | dependencies: 1562 | esbuild: 0.24.2 1563 | load-tsconfig: 0.2.5 1564 | 1565 | cac@6.7.14: {} 1566 | 1567 | chardet@0.7.0: {} 1568 | 1569 | chokidar@4.0.3: 1570 | dependencies: 1571 | readdirp: 4.1.1 1572 | 1573 | ci-info@3.9.0: {} 1574 | 1575 | color-convert@2.0.1: 1576 | dependencies: 1577 | color-name: 1.1.4 1578 | 1579 | color-name@1.1.4: {} 1580 | 1581 | commander@2.20.3: {} 1582 | 1583 | commander@4.1.1: {} 1584 | 1585 | commondir@1.0.1: {} 1586 | 1587 | consola@3.4.0: {} 1588 | 1589 | cross-spawn@7.0.6: 1590 | dependencies: 1591 | path-key: 3.1.1 1592 | shebang-command: 2.0.0 1593 | which: 2.0.2 1594 | 1595 | debug@4.4.0: 1596 | dependencies: 1597 | ms: 2.1.3 1598 | 1599 | deepmerge@4.3.1: {} 1600 | 1601 | detect-indent@6.1.0: {} 1602 | 1603 | dir-glob@3.0.1: 1604 | dependencies: 1605 | path-type: 4.0.0 1606 | 1607 | eastasianwidth@0.2.0: {} 1608 | 1609 | emoji-regex@8.0.0: {} 1610 | 1611 | emoji-regex@9.2.2: {} 1612 | 1613 | enquirer@2.4.1: 1614 | dependencies: 1615 | ansi-colors: 4.1.3 1616 | strip-ansi: 6.0.1 1617 | 1618 | esbuild@0.24.2: 1619 | optionalDependencies: 1620 | '@esbuild/aix-ppc64': 0.24.2 1621 | '@esbuild/android-arm': 0.24.2 1622 | '@esbuild/android-arm64': 0.24.2 1623 | '@esbuild/android-x64': 0.24.2 1624 | '@esbuild/darwin-arm64': 0.24.2 1625 | '@esbuild/darwin-x64': 0.24.2 1626 | '@esbuild/freebsd-arm64': 0.24.2 1627 | '@esbuild/freebsd-x64': 0.24.2 1628 | '@esbuild/linux-arm': 0.24.2 1629 | '@esbuild/linux-arm64': 0.24.2 1630 | '@esbuild/linux-ia32': 0.24.2 1631 | '@esbuild/linux-loong64': 0.24.2 1632 | '@esbuild/linux-mips64el': 0.24.2 1633 | '@esbuild/linux-ppc64': 0.24.2 1634 | '@esbuild/linux-riscv64': 0.24.2 1635 | '@esbuild/linux-s390x': 0.24.2 1636 | '@esbuild/linux-x64': 0.24.2 1637 | '@esbuild/netbsd-arm64': 0.24.2 1638 | '@esbuild/netbsd-x64': 0.24.2 1639 | '@esbuild/openbsd-arm64': 0.24.2 1640 | '@esbuild/openbsd-x64': 0.24.2 1641 | '@esbuild/sunos-x64': 0.24.2 1642 | '@esbuild/win32-arm64': 0.24.2 1643 | '@esbuild/win32-ia32': 0.24.2 1644 | '@esbuild/win32-x64': 0.24.2 1645 | 1646 | esprima@4.0.1: {} 1647 | 1648 | estree-walker@2.0.2: {} 1649 | 1650 | extendable-error@0.1.7: {} 1651 | 1652 | external-editor@3.1.0: 1653 | dependencies: 1654 | chardet: 0.7.0 1655 | iconv-lite: 0.4.24 1656 | tmp: 0.0.33 1657 | 1658 | fast-glob@3.3.3: 1659 | dependencies: 1660 | '@nodelib/fs.stat': 2.0.5 1661 | '@nodelib/fs.walk': 1.2.8 1662 | glob-parent: 5.1.2 1663 | merge2: 1.4.1 1664 | micromatch: 4.0.8 1665 | 1666 | fastq@1.19.0: 1667 | dependencies: 1668 | reusify: 1.0.4 1669 | 1670 | fdir@6.4.3(picomatch@4.0.2): 1671 | optionalDependencies: 1672 | picomatch: 4.0.2 1673 | 1674 | fill-range@7.1.1: 1675 | dependencies: 1676 | to-regex-range: 5.0.1 1677 | 1678 | find-up@4.1.0: 1679 | dependencies: 1680 | locate-path: 5.0.0 1681 | path-exists: 4.0.0 1682 | 1683 | foreground-child@3.3.0: 1684 | dependencies: 1685 | cross-spawn: 7.0.6 1686 | signal-exit: 4.1.0 1687 | 1688 | fs-extra@7.0.1: 1689 | dependencies: 1690 | graceful-fs: 4.2.11 1691 | jsonfile: 4.0.0 1692 | universalify: 0.1.2 1693 | 1694 | fs-extra@8.1.0: 1695 | dependencies: 1696 | graceful-fs: 4.2.11 1697 | jsonfile: 4.0.0 1698 | universalify: 0.1.2 1699 | 1700 | fsevents@2.3.3: 1701 | optional: true 1702 | 1703 | function-bind@1.1.2: {} 1704 | 1705 | glob-parent@5.1.2: 1706 | dependencies: 1707 | is-glob: 4.0.3 1708 | 1709 | glob@10.4.5: 1710 | dependencies: 1711 | foreground-child: 3.3.0 1712 | jackspeak: 3.4.3 1713 | minimatch: 9.0.5 1714 | minipass: 7.1.2 1715 | package-json-from-dist: 1.0.1 1716 | path-scurry: 1.11.1 1717 | 1718 | globby@11.1.0: 1719 | dependencies: 1720 | array-union: 2.1.0 1721 | dir-glob: 3.0.1 1722 | fast-glob: 3.3.3 1723 | ignore: 5.3.2 1724 | merge2: 1.4.1 1725 | slash: 3.0.0 1726 | 1727 | graceful-fs@4.2.11: {} 1728 | 1729 | hasown@2.0.2: 1730 | dependencies: 1731 | function-bind: 1.1.2 1732 | 1733 | human-id@4.1.1: {} 1734 | 1735 | iconv-lite@0.4.24: 1736 | dependencies: 1737 | safer-buffer: 2.1.2 1738 | 1739 | ignore@5.3.2: {} 1740 | 1741 | is-core-module@2.16.1: 1742 | dependencies: 1743 | hasown: 2.0.2 1744 | 1745 | is-extglob@2.1.1: {} 1746 | 1747 | is-fullwidth-code-point@3.0.0: {} 1748 | 1749 | is-glob@4.0.3: 1750 | dependencies: 1751 | is-extglob: 2.1.1 1752 | 1753 | is-module@1.0.0: {} 1754 | 1755 | is-number@7.0.0: {} 1756 | 1757 | is-reference@1.2.1: 1758 | dependencies: 1759 | '@types/estree': 1.0.6 1760 | 1761 | is-subdir@1.2.0: 1762 | dependencies: 1763 | better-path-resolve: 1.0.0 1764 | 1765 | is-windows@1.0.2: {} 1766 | 1767 | isexe@2.0.0: {} 1768 | 1769 | jackspeak@3.4.3: 1770 | dependencies: 1771 | '@isaacs/cliui': 8.0.2 1772 | optionalDependencies: 1773 | '@pkgjs/parseargs': 0.11.0 1774 | 1775 | joycon@3.1.1: {} 1776 | 1777 | js-yaml@3.14.1: 1778 | dependencies: 1779 | argparse: 1.0.10 1780 | esprima: 4.0.1 1781 | 1782 | jsonfile@4.0.0: 1783 | optionalDependencies: 1784 | graceful-fs: 4.2.11 1785 | 1786 | lilconfig@3.1.3: {} 1787 | 1788 | lines-and-columns@1.2.4: {} 1789 | 1790 | load-tsconfig@0.2.5: {} 1791 | 1792 | locate-path@5.0.0: 1793 | dependencies: 1794 | p-locate: 4.1.0 1795 | 1796 | lodash.sortby@4.7.0: {} 1797 | 1798 | lodash.startcase@4.4.0: {} 1799 | 1800 | lru-cache@10.4.3: {} 1801 | 1802 | magic-string@0.30.17: 1803 | dependencies: 1804 | '@jridgewell/sourcemap-codec': 1.5.0 1805 | 1806 | merge2@1.4.1: {} 1807 | 1808 | micromatch@4.0.8: 1809 | dependencies: 1810 | braces: 3.0.3 1811 | picomatch: 2.3.1 1812 | 1813 | minimatch@9.0.5: 1814 | dependencies: 1815 | brace-expansion: 2.0.1 1816 | 1817 | minipass@7.1.2: {} 1818 | 1819 | mri@1.2.0: {} 1820 | 1821 | ms@2.1.3: {} 1822 | 1823 | mz@2.7.0: 1824 | dependencies: 1825 | any-promise: 1.3.0 1826 | object-assign: 4.1.1 1827 | thenify-all: 1.6.0 1828 | 1829 | object-assign@4.1.1: {} 1830 | 1831 | os-tmpdir@1.0.2: {} 1832 | 1833 | outdent@0.5.0: {} 1834 | 1835 | p-filter@2.1.0: 1836 | dependencies: 1837 | p-map: 2.1.0 1838 | 1839 | p-limit@2.3.0: 1840 | dependencies: 1841 | p-try: 2.2.0 1842 | 1843 | p-locate@4.1.0: 1844 | dependencies: 1845 | p-limit: 2.3.0 1846 | 1847 | p-map@2.1.0: {} 1848 | 1849 | p-try@2.2.0: {} 1850 | 1851 | package-json-from-dist@1.0.1: {} 1852 | 1853 | package-manager-detector@0.2.9: {} 1854 | 1855 | path-exists@4.0.0: {} 1856 | 1857 | path-key@3.1.1: {} 1858 | 1859 | path-parse@1.0.7: {} 1860 | 1861 | path-scurry@1.11.1: 1862 | dependencies: 1863 | lru-cache: 10.4.3 1864 | minipass: 7.1.2 1865 | 1866 | path-type@4.0.0: {} 1867 | 1868 | picocolors@1.1.1: {} 1869 | 1870 | picomatch@2.3.1: {} 1871 | 1872 | picomatch@4.0.2: {} 1873 | 1874 | pify@4.0.1: {} 1875 | 1876 | pirates@4.0.6: {} 1877 | 1878 | postcss-load-config@6.0.1(yaml@2.4.2): 1879 | dependencies: 1880 | lilconfig: 3.1.3 1881 | optionalDependencies: 1882 | yaml: 2.4.2 1883 | 1884 | prettier@2.8.8: {} 1885 | 1886 | prettier@3.5.2: {} 1887 | 1888 | punycode@2.3.1: {} 1889 | 1890 | queue-microtask@1.2.3: {} 1891 | 1892 | randombytes@2.1.0: 1893 | dependencies: 1894 | safe-buffer: 5.2.1 1895 | 1896 | read-yaml-file@1.1.0: 1897 | dependencies: 1898 | graceful-fs: 4.2.11 1899 | js-yaml: 3.14.1 1900 | pify: 4.0.1 1901 | strip-bom: 3.0.0 1902 | 1903 | readdirp@4.1.1: {} 1904 | 1905 | regenerator-runtime@0.14.1: {} 1906 | 1907 | resolve-from@5.0.0: {} 1908 | 1909 | resolve@1.22.10: 1910 | dependencies: 1911 | is-core-module: 2.16.1 1912 | path-parse: 1.0.7 1913 | supports-preserve-symlinks-flag: 1.0.0 1914 | 1915 | reusify@1.0.4: {} 1916 | 1917 | rollup@4.34.8: 1918 | dependencies: 1919 | '@types/estree': 1.0.6 1920 | optionalDependencies: 1921 | '@rollup/rollup-android-arm-eabi': 4.34.8 1922 | '@rollup/rollup-android-arm64': 4.34.8 1923 | '@rollup/rollup-darwin-arm64': 4.34.8 1924 | '@rollup/rollup-darwin-x64': 4.34.8 1925 | '@rollup/rollup-freebsd-arm64': 4.34.8 1926 | '@rollup/rollup-freebsd-x64': 4.34.8 1927 | '@rollup/rollup-linux-arm-gnueabihf': 4.34.8 1928 | '@rollup/rollup-linux-arm-musleabihf': 4.34.8 1929 | '@rollup/rollup-linux-arm64-gnu': 4.34.8 1930 | '@rollup/rollup-linux-arm64-musl': 4.34.8 1931 | '@rollup/rollup-linux-loongarch64-gnu': 4.34.8 1932 | '@rollup/rollup-linux-powerpc64le-gnu': 4.34.8 1933 | '@rollup/rollup-linux-riscv64-gnu': 4.34.8 1934 | '@rollup/rollup-linux-s390x-gnu': 4.34.8 1935 | '@rollup/rollup-linux-x64-gnu': 4.34.8 1936 | '@rollup/rollup-linux-x64-musl': 4.34.8 1937 | '@rollup/rollup-win32-arm64-msvc': 4.34.8 1938 | '@rollup/rollup-win32-ia32-msvc': 4.34.8 1939 | '@rollup/rollup-win32-x64-msvc': 4.34.8 1940 | fsevents: 2.3.3 1941 | 1942 | run-parallel@1.2.0: 1943 | dependencies: 1944 | queue-microtask: 1.2.3 1945 | 1946 | safe-buffer@5.2.1: {} 1947 | 1948 | safer-buffer@2.1.2: {} 1949 | 1950 | semver@7.7.1: {} 1951 | 1952 | serialize-javascript@6.0.2: 1953 | dependencies: 1954 | randombytes: 2.1.0 1955 | 1956 | shebang-command@2.0.0: 1957 | dependencies: 1958 | shebang-regex: 3.0.0 1959 | 1960 | shebang-regex@3.0.0: {} 1961 | 1962 | signal-exit@4.1.0: {} 1963 | 1964 | slash@3.0.0: {} 1965 | 1966 | smob@1.5.0: {} 1967 | 1968 | source-map-support@0.5.21: 1969 | dependencies: 1970 | buffer-from: 1.1.2 1971 | source-map: 0.6.1 1972 | 1973 | source-map@0.6.1: {} 1974 | 1975 | source-map@0.8.0-beta.0: 1976 | dependencies: 1977 | whatwg-url: 7.1.0 1978 | 1979 | spawndamnit@3.0.1: 1980 | dependencies: 1981 | cross-spawn: 7.0.6 1982 | signal-exit: 4.1.0 1983 | 1984 | sprintf-js@1.0.3: {} 1985 | 1986 | string-width@4.2.3: 1987 | dependencies: 1988 | emoji-regex: 8.0.0 1989 | is-fullwidth-code-point: 3.0.0 1990 | strip-ansi: 6.0.1 1991 | 1992 | string-width@5.1.2: 1993 | dependencies: 1994 | eastasianwidth: 0.2.0 1995 | emoji-regex: 9.2.2 1996 | strip-ansi: 7.1.0 1997 | 1998 | strip-ansi@6.0.1: 1999 | dependencies: 2000 | ansi-regex: 5.0.1 2001 | 2002 | strip-ansi@7.1.0: 2003 | dependencies: 2004 | ansi-regex: 6.1.0 2005 | 2006 | strip-bom@3.0.0: {} 2007 | 2008 | sucrase@3.35.0: 2009 | dependencies: 2010 | '@jridgewell/gen-mapping': 0.3.8 2011 | commander: 4.1.1 2012 | glob: 10.4.5 2013 | lines-and-columns: 1.2.4 2014 | mz: 2.7.0 2015 | pirates: 4.0.6 2016 | ts-interface-checker: 0.1.13 2017 | 2018 | supports-preserve-symlinks-flag@1.0.0: {} 2019 | 2020 | term-size@2.2.1: {} 2021 | 2022 | terser@5.39.0: 2023 | dependencies: 2024 | '@jridgewell/source-map': 0.3.6 2025 | acorn: 8.14.0 2026 | commander: 2.20.3 2027 | source-map-support: 0.5.21 2028 | 2029 | thenify-all@1.6.0: 2030 | dependencies: 2031 | thenify: 3.3.1 2032 | 2033 | thenify@3.3.1: 2034 | dependencies: 2035 | any-promise: 1.3.0 2036 | 2037 | tinyexec@0.3.2: {} 2038 | 2039 | tinyglobby@0.2.10: 2040 | dependencies: 2041 | fdir: 6.4.3(picomatch@4.0.2) 2042 | picomatch: 4.0.2 2043 | 2044 | tmp@0.0.33: 2045 | dependencies: 2046 | os-tmpdir: 1.0.2 2047 | 2048 | to-regex-range@5.0.1: 2049 | dependencies: 2050 | is-number: 7.0.0 2051 | 2052 | tr46@1.0.1: 2053 | dependencies: 2054 | punycode: 2.3.1 2055 | 2056 | tree-kill@1.2.2: {} 2057 | 2058 | ts-interface-checker@0.1.13: {} 2059 | 2060 | tslib@2.8.1: {} 2061 | 2062 | tsup@8.3.6(typescript@5.7.3)(yaml@2.4.2): 2063 | dependencies: 2064 | bundle-require: 5.1.0(esbuild@0.24.2) 2065 | cac: 6.7.14 2066 | chokidar: 4.0.3 2067 | consola: 3.4.0 2068 | debug: 4.4.0 2069 | esbuild: 0.24.2 2070 | joycon: 3.1.1 2071 | picocolors: 1.1.1 2072 | postcss-load-config: 6.0.1(yaml@2.4.2) 2073 | resolve-from: 5.0.0 2074 | rollup: 4.34.8 2075 | source-map: 0.8.0-beta.0 2076 | sucrase: 3.35.0 2077 | tinyexec: 0.3.2 2078 | tinyglobby: 0.2.10 2079 | tree-kill: 1.2.2 2080 | optionalDependencies: 2081 | typescript: 5.7.3 2082 | transitivePeerDependencies: 2083 | - jiti 2084 | - supports-color 2085 | - tsx 2086 | - yaml 2087 | 2088 | typescript@5.7.3: {} 2089 | 2090 | undici-types@6.20.0: {} 2091 | 2092 | universalify@0.1.2: {} 2093 | 2094 | webidl-conversions@4.0.2: {} 2095 | 2096 | whatwg-url@7.1.0: 2097 | dependencies: 2098 | lodash.sortby: 4.7.0 2099 | tr46: 1.0.1 2100 | webidl-conversions: 4.0.2 2101 | 2102 | which@2.0.2: 2103 | dependencies: 2104 | isexe: 2.0.0 2105 | 2106 | wrap-ansi@7.0.0: 2107 | dependencies: 2108 | ansi-styles: 4.3.0 2109 | string-width: 4.2.3 2110 | strip-ansi: 6.0.1 2111 | 2112 | wrap-ansi@8.1.0: 2113 | dependencies: 2114 | ansi-styles: 6.2.1 2115 | string-width: 5.1.2 2116 | strip-ansi: 7.1.0 2117 | 2118 | yaml@2.4.2: 2119 | optional: true 2120 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import resolve from '@rollup/plugin-node-resolve'; 2 | import commonjs from '@rollup/plugin-commonjs'; 3 | import typescript from '@rollup/plugin-typescript'; 4 | import terser from '@rollup/plugin-terser'; 5 | 6 | export default { 7 | input: 'src/ass.ts', 8 | output: [ 9 | { 10 | file: 'dist/ass.min.js', 11 | format: 'iife', 12 | name: 'ASS', 13 | exports: 'named' 14 | } 15 | ], 16 | plugins: [typescript(), resolve(), commonjs(), terser()] 17 | }; 18 | -------------------------------------------------------------------------------- /src/ass.ts: -------------------------------------------------------------------------------- 1 | import { compile, type CompiledASS } from 'ass-compiler'; 2 | import { Renderer } from './renderer'; 3 | import type { OnInitSizes } from './types'; 4 | 5 | export type ASSOptions = { 6 | /** 7 | * The ass text 8 | */ 9 | assText: string; 10 | 11 | /** 12 | * The video to display the subtile on. 13 | * Can be either an `HTMLVideoElement` or `string` (html query selector) 14 | */ 15 | video: HTMLVideoElement | string; 16 | 17 | /** 18 | * List of fonts to load. This ensures that all the fonts 19 | * needed for the rendering are present and loaded into the document 20 | */ 21 | fonts?: Font[]; 22 | 23 | /** 24 | * Corresponds to the `z-index` to placed the Canvas renderer 25 | * > The renderer will always be added right after the `video` element 26 | */ 27 | zIndex?: number; 28 | 29 | /** 30 | * A Callback that is invoked when the preprocess of the ass text by render is done 31 | */ 32 | onReady?: () => void; 33 | 34 | /** 35 | * Type of logging 36 | * - `DEBUG` only debug type log will be displayed 37 | * - `DISABLE` no logging will be emitted (default) 38 | * - `VERBOSE` every log will be shown 39 | * - `WARN` only warning will be shown 40 | */ 41 | logging?: LOGTYPE; 42 | }; 43 | 44 | export type LOGTYPE = 'DISABLE' | 'VERBOSE' | 'DEBUG' | 'WARN'; 45 | 46 | export type FontStyle = { 47 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/ascentOverride) */ 48 | ascentOverride: string; 49 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/descentOverride) */ 50 | descentOverride: string; 51 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/display) */ 52 | display: FontDisplay; 53 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/family) */ 54 | family: string; 55 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/featureSettings) */ 56 | featureSettings: string; 57 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/lineGapOverride) */ 58 | lineGapOverride: string; 59 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/stretch) */ 60 | stretch: string; 61 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/style) */ 62 | style: string; 63 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/unicodeRange) */ 64 | unicodeRange: string; 65 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/variant) */ 66 | variant: string; 67 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/weight) */ 68 | weight: string; 69 | /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/FontFace/load) */ 70 | }; 71 | 72 | export type Font = { 73 | family: string; 74 | url: string; 75 | descriptors?: Partial; 76 | }; 77 | 78 | /** 79 | * @class ASS 80 | * 81 | * ASS is an ass/ssa subtitle renderer. 82 | * 83 | * It uses a `canvas` that is placed on top of 84 | * the targeted video element 85 | * */ 86 | export default class ASS { 87 | assText: string; 88 | private video: HTMLVideoElement | string; 89 | videoElement: HTMLVideoElement | null = null; 90 | private renderer: Renderer | null = null; 91 | private ro: ResizeObserver | null = null; 92 | private fonts?: Font[]; 93 | private zIndex?: number; 94 | private onReady?: () => void; 95 | private logging: LOGTYPE = 'DISABLE'; 96 | private compiledAss: CompiledASS; 97 | 98 | constructor(options: ASSOptions) { 99 | this.assText = options.assText; 100 | this.compiledAss = compile(this.assText, {}); 101 | this.video = options.video; 102 | this.fonts = options.fonts; 103 | this.zIndex = options.zIndex; 104 | this.onReady = options.onReady; 105 | if (options.logging) this.logging = options.logging; 106 | } 107 | 108 | /** 109 | * Start the ass rendering process 110 | */ 111 | async render() { 112 | if (typeof this.video == 'string') { 113 | this.videoElement = document.querySelector(this.video); 114 | if (this.videoElement === null) { 115 | throw new Error('Unable to find the video element'); 116 | } 117 | } else { 118 | this.videoElement = this.video; 119 | } 120 | 121 | const sizes = this.setCanvasSize(); 122 | 123 | if (typeof this.fonts !== 'undefined') { 124 | await this.loadFonts(this.fonts); 125 | } 126 | 127 | if (this.videoElement) { 128 | this.renderer = new Renderer( 129 | this.compiledAss, 130 | sizes, 131 | this.videoElement, 132 | this.logging, 133 | this.zIndex 134 | ); 135 | this.setCanvasSize(); 136 | this.videoElement.addEventListener('loadedmetadata', this.setCanvasSize.bind(this)); 137 | 138 | this.ro = new ResizeObserver(this.setCanvasSize.bind(this)); 139 | this.ro.observe(this.videoElement); 140 | 141 | await this.renderer.warmup(); 142 | if (this.onReady) { 143 | this.onReady(); 144 | } 145 | 146 | await this.renderer.startRendering(); 147 | } 148 | } 149 | 150 | /** 151 | * Stop the rendering 152 | */ 153 | destroy() { 154 | this.videoElement?.removeEventListener('loadedmetadata', this.setCanvasSize.bind(this)); 155 | this.ro?.disconnect(); 156 | 157 | this.renderer?.destroy(); 158 | this.renderer = null; 159 | } 160 | 161 | private setCanvasSize() { 162 | const { videoWidth, videoHeight, offsetTop, offsetLeft } = this 163 | .videoElement as HTMLVideoElement; 164 | const aspectRatio = videoWidth / videoHeight; 165 | 166 | const maxWidth = this.videoElement?.clientWidth || 0; 167 | const maxHeight = this.videoElement?.clientHeight || 0; 168 | 169 | let width = maxWidth; 170 | let height = maxHeight; 171 | let x = offsetLeft; 172 | let y = offsetTop; 173 | 174 | if (maxHeight * aspectRatio > maxWidth) { 175 | width = maxWidth; 176 | height = width / aspectRatio; 177 | y += (maxHeight - height) / 2; 178 | } else { 179 | height = maxHeight; 180 | width = height * aspectRatio; 181 | x += (maxWidth - width) / 2; 182 | } 183 | 184 | const sizes = { 185 | width, 186 | height, 187 | x, 188 | y 189 | } as OnInitSizes; 190 | 191 | if (this.renderer?.renderDiv) { 192 | this.renderer.renderDiv.style.width = width + 'px'; 193 | this.renderer.renderDiv.style.height = height + 'px'; 194 | this.renderer.renderDiv.style.top = y + 'px'; 195 | this.renderer.renderDiv.style.left = x + 'px'; 196 | } 197 | 198 | this.renderer?.layers.forEach((layer) => { 199 | layer.canvas.width = width; 200 | layer.canvas.height = height; 201 | }); 202 | 203 | return sizes; 204 | } 205 | 206 | private async loadFonts(fonts: Font[]) { 207 | for (const font of fonts) { 208 | try { 209 | const loaded = await this.loadFont(font); 210 | if (loaded) { 211 | if (this.logging == 'VERBOSE') 212 | console.info(`Font ${font.family} loaded from ${font.url}`); 213 | } else { 214 | if (this.logging == 'VERBOSE' || this.logging == 'WARN') 215 | console.warn(`Unable to load font ${font.family} from ${font.url}`); 216 | } 217 | } catch (e) { 218 | if (this.logging == 'VERBOSE' || this.logging == 'WARN') { 219 | console.warn(`Unable to load font ${font.family} from ${font.url}`); 220 | console.warn(e); 221 | } 222 | } 223 | } 224 | } 225 | 226 | private async getFontUrl(fontUrl: string) { 227 | const response = await fetch(fontUrl); 228 | const blob = await response.blob(); 229 | return URL.createObjectURL(blob); 230 | } 231 | 232 | private async loadFont(font: Font) { 233 | const url = await this.getFontUrl(font.url); 234 | const fontFace = new FontFace(font.family, `url(${url})`, font.descriptors || {}); 235 | const loadedFace = await fontFace.load(); 236 | // @ts-ignore 237 | document.fonts.add(loadedFace); 238 | return fontFace.status === 'loaded'; 239 | } 240 | } 241 | -------------------------------------------------------------------------------- /src/renderer.ts: -------------------------------------------------------------------------------- 1 | import type { CompiledASS, CompiledASSStyle, Dialogue, DialogueSlice } from 'ass-compiler'; 2 | import type { CompiledTag } from 'ass-compiler/types/tags'; 3 | 4 | import type { 5 | StyleDescriptor, 6 | Styles, 7 | Position, 8 | OnInitSizes, 9 | Layer, 10 | Margin, 11 | Char, 12 | Word, 13 | FadeAnimation, 14 | CustomAnimation 15 | } from './types'; 16 | import { CHARKIND, LOGTYPE, Align, Baseline, FadeKind } from './types'; 17 | import { 18 | ruleOfThree, 19 | blendAlpha, 20 | convertAegisubColorToHex, 21 | swapBBGGRR, 22 | newCanvas, 23 | newRender, 24 | Vector2, 25 | stringHash, 26 | chunkCharWidth, 27 | chunkCharToString, 28 | vectorLerp, 29 | getOpacity, 30 | getOpacityComplex, 31 | lerp, 32 | parseAlpha 33 | } from './utils'; 34 | 35 | type PreProceesedAss = { 36 | start: number; 37 | layer: number; 38 | end: number; 39 | style: string; 40 | margin: Margin; 41 | pos?: Position; 42 | move?: MoveAnimation; 43 | fade?: FadeAnimation; 44 | rotationOrigin?: Vector2; 45 | alignment: number; 46 | chars: Char[]; 47 | }; 48 | 49 | type MoveAnimation = { 50 | // x1: number; 51 | // y1: number; 52 | from: Vector2; 53 | // x2: number; 54 | //y2: number; 55 | to: Vector2; 56 | // t1: number; 57 | start: number; 58 | //t2: number; 59 | end: number; 60 | }; 61 | 62 | export class Renderer { 63 | compiledASS: CompiledASS; 64 | renderDiv: HTMLDivElement; 65 | layers: Layer[]; 66 | numberOfLayers: number; 67 | video: HTMLVideoElement; 68 | playerResX: number; 69 | playerResY: number; 70 | stop: boolean = false; 71 | animationHandle: number | null = null; 72 | _log: LOGTYPE; 73 | ppass: PreProceesedAss[] = []; 74 | styles: Styles; 75 | collisions: 'Normal' | 'Reverse' = 'Normal'; 76 | dt = 0; 77 | previous = 0; 78 | currentTime = 0; 79 | 80 | constructor( 81 | ass: CompiledASS, 82 | sizes: OnInitSizes, 83 | video: HTMLVideoElement, 84 | log: LOGTYPE, 85 | zIndex?: number 86 | ) { 87 | this._log = log; 88 | this.compiledASS = ass; 89 | this.styles = ass.styles; 90 | this.collisions = ass.collisions; 91 | if (this._log === 'DEBUG') { 92 | this.log('DEBUG', this.compiledASS); 93 | } 94 | this.playerResX = this.compiledASS.width; 95 | this.playerResY = this.compiledASS.height; 96 | this.renderDiv = newRender(sizes.y, sizes.x, sizes.width, sizes.height, zIndex, video); 97 | const background = newCanvas(sizes.width, sizes.height, -1, 'background', this.renderDiv); 98 | const bgCtx = background.getContext('2d') as CanvasRenderingContext2D; 99 | if (bgCtx === null) { 100 | throw new Error('Unable to initilize the Canvas 2D context'); 101 | } 102 | this.layers = [ 103 | { 104 | canvas: background, 105 | ctx: bgCtx 106 | } 107 | ]; 108 | 109 | this.numberOfLayers = this.findTotalLayers(ass); 110 | this.insertLayers(sizes, background); 111 | this.video = video; 112 | } 113 | 114 | insertLayers(sizes: OnInitSizes, insertAfter: HTMLCanvasElement) { 115 | for (let i = 0; i < this.numberOfLayers; i++) { 116 | const canvas = newCanvas(sizes.width, sizes.height, i, 'frame', undefined, insertAfter); 117 | const ctx = canvas.getContext('2d') as CanvasRenderingContext2D; 118 | if (ctx === null) { 119 | throw new Error('Unable to initilize the Canvas 2D context'); 120 | } 121 | 122 | //@ts-ignore 123 | ctx.textRendering = 'geometricPrecision'; 124 | 125 | this.layers.push({ 126 | canvas: canvas, 127 | ctx: ctx 128 | }); 129 | } 130 | } 131 | 132 | getLayer(l: number): Layer | null { 133 | for (let i = 1; i < this.layers.length; i++) { 134 | if (this.layers[i]?.canvas.dataset.layer == l.toString()) { 135 | return this.layers[i] as Layer; 136 | } 137 | } 138 | return null; 139 | } 140 | 141 | findTotalLayers(ass: CompiledASS) { 142 | let maxLayer = 1; 143 | ass.dialogues.forEach((dialogue) => { 144 | if (dialogue.layer >= maxLayer) maxLayer++; 145 | }); 146 | 147 | return maxLayer; 148 | } 149 | 150 | async warmup() { 151 | const { dialogues } = this.compiledASS; 152 | const canvas = document.createElement('canvas'); 153 | canvas.height = this.playerResY; 154 | canvas.width = this.playerResX; 155 | const ctx = canvas.getContext('2d') as CanvasRenderingContext2D; 156 | const computelayer: Layer = { 157 | ctx, 158 | canvas 159 | }; 160 | 161 | computelayer.canvas.width = this.playerResX; 162 | computelayer.canvas.height = this.playerResY; 163 | console.debug(dialogues); 164 | 165 | for (let i = 0; i < dialogues.length; i++) { 166 | const dia = dialogues[i] as Dialogue; 167 | const { layer, alignment, start, end, style, margin, slices, pos, move, org, fade } = dia; 168 | let movAnim: MoveAnimation | undefined; 169 | let rotOrg: Vector2 | undefined; 170 | let fadeAnim: FadeAnimation | undefined; 171 | 172 | if (move) { 173 | movAnim = { 174 | from: new Vector2(move.x1, move.y1), 175 | to: new Vector2(move.x2, move.y2), 176 | start: move.t1, 177 | end: move.t2 178 | }; 179 | } 180 | 181 | if (org) { 182 | rotOrg = new Vector2(org.x, org.y); 183 | } 184 | 185 | if (fade) { 186 | switch (fade.type) { 187 | case 'fad': 188 | fadeAnim = { type: FadeKind.Simple, fadein: fade.t1, fadeout: fade.t2 }; 189 | break; 190 | case 'fade': 191 | let { a1, a2, a3, t1, t2, t3, t4 } = fade; 192 | fadeAnim = { type: FadeKind.Complex, a1, a2, a3, t1, t2, t3, t4 }; 193 | break; 194 | } 195 | } 196 | 197 | this.ppass.push({ 198 | start, 199 | layer, 200 | end, 201 | style, 202 | margin, 203 | alignment, 204 | pos, 205 | move: movAnim, 206 | fade: fadeAnim, 207 | rotationOrigin: rotOrg, 208 | chars: this.processSlices(alignment, slices, computelayer) 209 | }); 210 | } 211 | } 212 | 213 | processSlices(alignment: number, slices: DialogueSlice[], layer: Layer): Char[] { 214 | let chars: Char[] = []; 215 | slices.forEach((slice) => { 216 | const { style, fragments } = slice; 217 | let font = this.computeStyle(style, alignment, layer); 218 | 219 | let _frag: Char[] = []; 220 | 221 | fragments.forEach((frag) => { 222 | this.applyOverrideTag(frag.tag, font); 223 | this.applyFont(font, layer); 224 | 225 | //@ts-ignore 226 | const text = frag.text.replaceAll('\\N', '\n').split(''); 227 | 228 | let ord = 0; 229 | let chars: Char[] = []; 230 | 231 | for (let i = 0; i < text.length; i++) { 232 | const char = text[i] as string; 233 | if (char == '\n') { 234 | chars.push({ 235 | kind: CHARKIND.NEWLINE 236 | }); 237 | ord = 0; 238 | } else { 239 | chars.push({ 240 | kind: CHARKIND.NORMAL, 241 | pos: new Vector2(), 242 | c: char, 243 | ord, 244 | w: 0, 245 | style, 246 | tag: frag.tag 247 | }); 248 | 249 | ord += 1; 250 | } 251 | } 252 | 253 | _frag = _frag.concat(chars); 254 | }); 255 | 256 | chars = chars.concat(_frag); 257 | }); 258 | 259 | return chars; 260 | } 261 | 262 | sublog(type: LOGTYPE, ...message: any) { 263 | switch (type) { 264 | case 'DISABLE': 265 | break; 266 | case 'VERBOSE': 267 | console.info(type, ...message); 268 | break; 269 | case 'DEBUG': 270 | console.debug(type, ...message); 271 | break; 272 | case 'WARN': 273 | console.warn(type, ...message); 274 | break; 275 | } 276 | } 277 | 278 | log(type: LOGTYPE, ...message: any) { 279 | switch (this._log) { 280 | case 'DISABLE': 281 | break; 282 | case 'VERBOSE': 283 | this.sublog(type, message); 284 | break; 285 | case 'DEBUG': 286 | if (type == 'DEBUG') { 287 | this.sublog(type, message); 288 | } 289 | break; 290 | case 'WARN': 291 | if (type == 'WARN') { 292 | this.sublog(type, message); 293 | } 294 | break; 295 | } 296 | } 297 | 298 | async startRendering() { 299 | window.requestAnimationFrame((timestamp) => { 300 | this.previous = timestamp; 301 | this.animationHandle = requestAnimationFrame(this.render.bind(this)); 302 | }); 303 | } 304 | 305 | render(timestamp: number) { 306 | if (this.stop === true) { 307 | if (this.animationHandle) { 308 | this.renderDiv.remove(); 309 | cancelAnimationFrame(this.animationHandle); 310 | } 311 | } else { 312 | this.dt = (timestamp - this.previous) / 1000.0; 313 | this.previous = timestamp; 314 | this.display(this.video.currentTime); 315 | this.animationHandle = requestAnimationFrame(this.render.bind(this)); 316 | } 317 | } 318 | 319 | destroy() { 320 | // console.debug('STOPPED::'); 321 | this.stop = true; 322 | } 323 | 324 | display(time: number) { 325 | this.currentTime = time; 326 | this.clear(); 327 | const slicesToDisplay = this.getSlices(time); 328 | slicesToDisplay.forEach((dialogue) => { 329 | this.showDialogue(dialogue, time); 330 | }); 331 | } 332 | 333 | charsToString(chars: Char[]): string { 334 | return chars.reduce((acc, v) => { 335 | return (acc += v.kind == CHARKIND.NEWLINE ? '\n' : v.c); 336 | }, ''); 337 | } 338 | 339 | getSlices(time: number): PreProceesedAss[] { 340 | return this.ppass.filter((dialogue) => { 341 | return dialogue.start <= time && dialogue.end >= time; 342 | }); 343 | } 344 | 345 | getLineHeights(layer: Layer, lines: Char[][]): number[] { 346 | let heights: number[] = []; 347 | 348 | let currentMaxHeight = 0; 349 | lines.forEach((line) => { 350 | line.forEach((char) => { 351 | if (char.kind === CHARKIND.NORMAL) { 352 | let font = this.computeStyle(char.style, 1, layer); 353 | this.applyOverrideTag(char.tag, font); 354 | this.applyFont(font, layer); 355 | let calc = 356 | layer.ctx.measureText(char.c).fontBoundingBoxAscent + 357 | layer.ctx.measureText(char.c).fontBoundingBoxDescent; 358 | if (calc > currentMaxHeight) { 359 | currentMaxHeight = calc; 360 | } 361 | } 362 | }); 363 | heights.push(currentMaxHeight); 364 | currentMaxHeight = 0; 365 | }); 366 | 367 | return heights; 368 | } 369 | 370 | countLines(chars: Char[]): number { 371 | return chars.filter((c) => c.kind === CHARKIND.NEWLINE).length + 1; 372 | } 373 | 374 | lineWidth(layer: Layer, chars: Char[]) { 375 | let w = 0; 376 | chars.forEach((char) => { 377 | if (char.kind === CHARKIND.NORMAL) { 378 | let font = this.computeStyle(char.style, 1, layer); 379 | this.applyOverrideTag(char.tag, font); 380 | this.applyFont(font, layer); 381 | w += layer.ctx.measureText(char.c).width + font.t.fsp; 382 | } 383 | }); 384 | 385 | return w; 386 | } 387 | 388 | lines(chars: Char[]): Char[][] { 389 | let lines: Char[][] = []; 390 | let buff: Char[] = []; 391 | 392 | chars.forEach((char) => { 393 | switch (char.kind) { 394 | case CHARKIND.NEWLINE: 395 | lines.push(buff); 396 | buff = []; 397 | break; 398 | case CHARKIND.NORMAL: 399 | buff.push(char); 400 | break; 401 | } 402 | }); 403 | 404 | if (buff.length > 0) { 405 | lines.push(buff); 406 | } 407 | 408 | return lines; 409 | } 410 | 411 | showDialogue(d: PreProceesedAss, time: number) { 412 | const layer = this.getLayer(d.layer); 413 | if (layer) { 414 | let font = this.computeStyle(d.style, d.alignment, layer); 415 | 416 | const lines = this.lines(d.chars); 417 | const lineHeights = this.getLineHeights(layer, lines); 418 | const lineHeight = Math.max(...lineHeights); 419 | const linesCount = this.countLines(d.chars); 420 | const totalHeight = lineHeight * linesCount; 421 | let cX = 0; 422 | let cY = 0; 423 | let baseX = 0; 424 | let currentOpacity = 1; 425 | 426 | let customPosition = false; 427 | let rotationOrigin: Vector2 | undefined; 428 | const Xratio = layer.canvas.width / this.playerResX; 429 | const Yratio = layer.canvas.height / this.playerResY; 430 | 431 | if (d.pos) { 432 | customPosition = true; 433 | baseX = d.pos.x * Xratio; 434 | cX = baseX; 435 | cY = d.pos.y * Yratio; 436 | } 437 | 438 | if (d.move) { 439 | customPosition = true; 440 | 441 | let startPosition = new Vector2(d.move.from.x * Xratio, d.move.from.y * Yratio); 442 | let endPosition = new Vector2(d.move.to.x * Xratio, d.move.to.y * Yratio); 443 | let actualPosition = vectorLerp( 444 | startPosition, 445 | endPosition, 446 | (time - d.start) / (d.end - d.start) 447 | ); 448 | 449 | baseX = actualPosition.x; 450 | cX = baseX; 451 | cY = actualPosition.y; 452 | } 453 | 454 | if (d.rotationOrigin) 455 | rotationOrigin = new Vector2(d.rotationOrigin.x * Xratio, d.rotationOrigin.y * Yratio); 456 | 457 | if (d.fade) { 458 | switch (d.fade.type) { 459 | case FadeKind.Simple: 460 | currentOpacity = getOpacity(d.fade, d.start * 1000, d.end * 1000, time * 1000); 461 | break; 462 | case FadeKind.Complex: 463 | currentOpacity = getOpacityComplex(d.fade, d.start * 1000, d.end * 1000, time * 1000); 464 | break; 465 | } 466 | } 467 | 468 | d.chars.forEach((char) => { 469 | switch (char.kind) { 470 | case CHARKIND.NEWLINE: 471 | cX = baseX; 472 | cY += lineHeight; 473 | break; 474 | case CHARKIND.NORMAL: 475 | font = this.computeStyle(char.style, d.alignment, layer); 476 | this.applyOverrideTag(char.tag, font); 477 | this.applyFont(font, layer); 478 | const w = layer.ctx.measureText(char.c).width + font.t.fsp; 479 | char.pos.x = cX; 480 | char.pos.y = cY; 481 | char.w = w; 482 | cX += w; 483 | break; 484 | } 485 | }); 486 | 487 | const margin = this.upscaleMargin(d.margin); 488 | 489 | lines.forEach((line) => { 490 | // WARN: To debug 491 | const lineWidth = this.lineWidth(layer, line); 492 | 493 | if (!customPosition) { 494 | switch (font.textAlign) { 495 | case Align.Left: 496 | line.forEach((char) => { 497 | if (char.kind == CHARKIND.NORMAL) char.pos.x += margin.left; 498 | }); 499 | break; 500 | case Align.Center: 501 | line.forEach((char) => { 502 | if (char.kind == CHARKIND.NORMAL) 503 | char.pos.x += (layer.canvas.width - lineWidth) / 2; 504 | }); 505 | break; 506 | case Align.Right: 507 | line.forEach((char) => { 508 | if (char.kind == CHARKIND.NORMAL) 509 | char.pos.x += layer.canvas.width - lineWidth - margin.right; 510 | }); 511 | break; 512 | default: 513 | line.forEach((char) => { 514 | if (char.kind == CHARKIND.NORMAL) char.pos.x += margin.left; 515 | }); 516 | break; 517 | } 518 | switch (font.textBaseline) { 519 | case Baseline.Bottom: 520 | line.forEach((char) => { 521 | if (char.kind == CHARKIND.NORMAL) 522 | char.pos.y += 523 | layer.canvas.height - 524 | (lines.length > 1 ? totalHeight / lines.length : 0) - 525 | margin.vertical; 526 | }); 527 | break; 528 | case Baseline.Middle: 529 | line.forEach((char) => { 530 | if (char.kind == CHARKIND.NORMAL) 531 | char.pos.y += 532 | (layer.canvas.height - totalHeight) / 2 + 533 | (lines.length > 1 ? totalHeight / lines.length : lineHeight); 534 | }); 535 | break; 536 | case Baseline.Top: 537 | line.forEach((char) => { 538 | if (char.kind == CHARKIND.NORMAL) char.pos.y += margin.vertical + lineHeight / 2; 539 | }); 540 | break; 541 | default: 542 | line.forEach((char) => { 543 | if (char.kind == CHARKIND.NORMAL) 544 | char.pos.y += 545 | layer.canvas.height - 546 | (lines.length > 1 ? totalHeight / lines.length : 0) - 547 | margin.vertical; 548 | }); 549 | break; 550 | } 551 | } else { 552 | switch (font.textAlign) { 553 | case Align.Left: 554 | break; 555 | case Align.Center: 556 | line.forEach((char) => { 557 | if (char.kind == CHARKIND.NORMAL) char.pos.x -= lineWidth / 2; 558 | }); 559 | break; 560 | case Align.Right: 561 | // line.forEach((char) => { 562 | // if (char.kind == CHARKIND.NORMAL) char.pos.x += lineWidth; 563 | // }); 564 | break; 565 | default: 566 | break; 567 | } 568 | } 569 | }); 570 | 571 | let currentWord: Char[] = []; 572 | let currentFont: StyleDescriptor | null = null; 573 | let words: Word[] = []; 574 | 575 | let currentHash = 0; 576 | 577 | d.chars.forEach((char) => { 578 | if (char.kind == CHARKIND.NORMAL) { 579 | let font = this.computeStyle(char.style, d.alignment, layer); 580 | this.applyOverrideTag(char.tag, font); 581 | 582 | let fHash = this.getFontHash(font); 583 | 584 | if (currentHash !== fHash) { 585 | if (currentWord.length > 0) { 586 | if (currentFont !== null) { 587 | words.push({ 588 | font: currentFont, 589 | value: currentWord, 590 | w: chunkCharWidth(currentWord) 591 | }); 592 | 593 | currentWord = [char]; 594 | currentFont = font; 595 | currentHash = fHash; 596 | } 597 | } else { 598 | currentFont = font; 599 | currentWord.push(char); 600 | currentHash = fHash; 601 | } 602 | } else { 603 | currentFont = font; 604 | currentWord.push(char); 605 | currentHash = fHash; 606 | } 607 | } else { 608 | if (currentFont !== null) { 609 | words.push({ 610 | font: currentFont, 611 | value: currentWord, 612 | w: chunkCharWidth(currentWord) 613 | }); 614 | 615 | currentWord = []; 616 | currentFont = null; 617 | } 618 | } 619 | }); 620 | 621 | if (currentWord.length > 0) { 622 | if (currentFont !== null) { 623 | words.push({ 624 | font: currentFont, 625 | value: currentWord, 626 | w: chunkCharWidth(currentWord) 627 | }); 628 | 629 | currentWord = []; 630 | currentFont = null; 631 | } 632 | } 633 | 634 | words.forEach((word) => { 635 | word.font.opacity = currentOpacity; 636 | layer.ctx.save(); 637 | this.drawWord(word, time, d.start, layer); 638 | layer.ctx.restore(); 639 | }); 640 | } 641 | } 642 | 643 | getFontHash(font: StyleDescriptor): number { 644 | return stringHash(JSON.stringify(font)); 645 | } 646 | 647 | drawWord(word: Word, time: number, startTime: number, layer: Layer, debug = false) { 648 | let str = chunkCharToString(word.value); 649 | for (let i = 0; i < word.font.customAnimations.length; i++) { 650 | const ca = word.font.customAnimations[i] as CustomAnimation; 651 | if (startTime * 1000 + ca.t1 <= time * 1000 && time * 1000 <= startTime * 1000 + ca.t2) { 652 | const end = startTime * 1000 + ca.t2; 653 | const start = startTime * 1000 + ca.t1; 654 | const t = (time * 1000 - start) / (end - start); 655 | 656 | for (const field in ca.tag) { 657 | switch (field) { 658 | case 'a1': 659 | case 'a3': 660 | case 'a4': 661 | word.font.colors[field] = lerp( 662 | 255, 663 | Math.abs(parseAlpha(ca.tag[field] as string) - 255), 664 | t 665 | ); 666 | break; 667 | case 'blur': 668 | case 'xshad': 669 | case 'yshad': 670 | case 'xbord': 671 | case 'ybord': 672 | word.font[field] = lerp(0, ca.tag[field] as number, t); 673 | break; 674 | case 'fax': 675 | case 'fay': 676 | case 'frx': 677 | case 'fry': 678 | case 'frz': 679 | case 'fscx': 680 | case 'fscy': 681 | word.font.t[field] = lerp(0, ca.tag[field] as number, t); 682 | break; 683 | case 'fs': 684 | word.font.fontsize = this.upscale( 685 | lerp(0, ca.tag[field] as number, t), 686 | this.playerResY, 687 | this.layers[0]?.canvas.height || 0 688 | ); 689 | break; 690 | case 'fsp': 691 | word.font.t.fsp = this.upscale( 692 | lerp(0, ca.tag[field] as number, t), 693 | this.playerResX, 694 | this.layers[0]?.canvas.width || this.playerResX 695 | ); 696 | break; 697 | default: 698 | break; 699 | } 700 | } 701 | } 702 | } 703 | 704 | this.applyFont(word.font, layer); 705 | const wordHead = word.value[0] as Char; 706 | 707 | if (wordHead.kind === CHARKIND.NORMAL) { 708 | if (word.font.borderStyle !== 3) { 709 | if (word.font.xbord !== 0 || word.font.ybord !== 0) { 710 | layer.ctx.strokeText(str, wordHead.pos.x, wordHead.pos.y); 711 | } 712 | } 713 | 714 | let metrics = layer.ctx.measureText(str); 715 | 716 | layer.ctx.fillText(str, wordHead.pos.x, wordHead.pos.y); 717 | 718 | if (word.font.underline) { 719 | const y = wordHead.pos.y + metrics.emHeightDescent; 720 | layer.ctx.fillRect(wordHead.pos.x, y, metrics.width, (layer.canvas.height * 0.2) / 100); 721 | } 722 | if (word.font.strikeout) { 723 | const y = wordHead.pos.y - metrics.hangingBaseline / 2; 724 | layer.ctx.shadowOffsetX = 0; 725 | layer.ctx.shadowOffsetY = 0; 726 | layer.ctx.fillRect(wordHead.pos.x, y, metrics.width, (layer.canvas.height * 0.2) / 100); 727 | } 728 | 729 | if (word.font.borderStyle === 3) { 730 | this.drawTextBackground( 731 | wordHead.pos, 732 | metrics.actualBoundingBoxAscent + metrics.fontBoundingBoxDescent, 733 | metrics.width, 734 | word.font 735 | ); 736 | } 737 | } 738 | } 739 | 740 | drawTextBackground(pos: Vector2, height: number, width: number, font: StyleDescriptor) { 741 | const layer = this.layers[0] as Layer; 742 | layer.ctx.save(); 743 | layer.ctx.beginPath(); 744 | layer.ctx.fillStyle = font.colors.c2; 745 | layer.ctx.fillRect(pos.x, pos.y - height, width, height); 746 | layer.ctx.closePath(); 747 | layer.ctx.restore(); 748 | } 749 | 750 | upscaleY(y: number, baseCanvasHeight: number) { 751 | const canvasHeight = this.layers[0]?.canvas.height || this.playerResY; 752 | return (canvasHeight * y) / baseCanvasHeight; 753 | } 754 | upscaleX(x: number, baseCanvasWidth: number) { 755 | const canvasWidth = this.layers[0]?.canvas.width || this.playerResX; 756 | return (canvasWidth * x) / baseCanvasWidth; 757 | } 758 | 759 | clearLayer(layer: number) { 760 | this.layers[layer]?.ctx.clearRect( 761 | 0, 762 | 0, 763 | this.layers[layer]?.canvas.width as number, 764 | this.layers[layer]?.canvas.height as number 765 | ); 766 | } 767 | 768 | clear() { 769 | this.layers.forEach((layer) => { 770 | layer.ctx.clearRect(0, 0, layer.canvas.width, layer.canvas.height); 771 | }); 772 | } 773 | 774 | upscalePosition(pos: Position) { 775 | return { 776 | x: this.upscale(pos.x, this.playerResX, this.layers[0]?.canvas.width || this.playerResX), 777 | y: this.upscale(pos.y, this.playerResY, this.layers[0]?.canvas.height || this.playerResY) 778 | }; 779 | } 780 | 781 | upscaleMargin(margin: Margin) { 782 | return { 783 | left: this.upscale( 784 | margin.left, 785 | this.playerResX, 786 | this.layers[0]?.canvas.width || this.playerResX 787 | ), 788 | right: this.upscale( 789 | margin.right, 790 | this.playerResX, 791 | this.layers[0]?.canvas.width || this.playerResX 792 | ), 793 | vertical: this.upscale( 794 | margin.vertical, 795 | this.playerResY, 796 | this.layers[0]?.canvas.height || this.playerResY 797 | ) 798 | }; 799 | } 800 | 801 | applyOverrideTag(tag: CompiledTag, font: StyleDescriptor) { 802 | if (tag.b !== undefined) font.bold = tag.b === 1; 803 | if (tag.i !== undefined) font.italic = tag.i === 1; 804 | if (tag.u !== undefined) font.underline = tag.u === 1; 805 | if (tag.s !== undefined) font.strikeout = tag.s === 1; 806 | if (tag.fn !== undefined) font.fontname = tag.fn; 807 | if (tag.q !== undefined) font.t.q = tag.q; 808 | if (tag.fs !== undefined) 809 | font.fontsize = this.upscale(tag.fs, this.playerResY, this.layers[0]?.canvas.height || 0); 810 | if (tag.fscx !== undefined) font.t.fscx = tag.fscx; 811 | if (tag.fscy !== undefined) font.t.fscy = tag.fscy; 812 | if (tag.frz !== undefined) font.t.frz = tag.frz; 813 | if (tag.frx !== undefined) font.t.frx = tag.frx; 814 | if (tag.fry !== undefined) font.t.fry = tag.fry; 815 | if (tag.fax !== undefined) font.t.fax = tag.fax; 816 | if (tag.fay !== undefined) font.t.fay = tag.fay; 817 | if (tag.fsp !== undefined) { 818 | font.t.fsp = this.upscale( 819 | tag.fsp, 820 | this.playerResX, 821 | this.layers[0]?.canvas.width || this.playerResX 822 | ); 823 | } 824 | 825 | if (tag.t !== undefined) font.customAnimations = tag.t; 826 | 827 | if (tag.c1 !== undefined) font.colors.c1 = swapBBGGRR(tag.c1); 828 | if (tag.c3 !== undefined) font.colors.c3 = swapBBGGRR(tag.c3); 829 | if (tag.c4 !== undefined) font.colors.c4 = swapBBGGRR(tag.c4); 830 | if (tag.a1 !== undefined) font.colors.a1 = parseAlpha(tag.a1); 831 | if (tag.a3 !== undefined) font.colors.a3 = parseAlpha(tag.a3); 832 | if (tag.a4 !== undefined) font.colors.a4 = parseAlpha(tag.a4); 833 | if (tag.xshad !== undefined) font.xshad = tag.xshad; 834 | if (tag.yshad !== undefined) font.yshad = tag.yshad; 835 | if (tag.xbord !== undefined) font.xbord = tag.xbord; 836 | if (tag.ybord !== undefined) font.ybord = tag.ybord; 837 | if (tag.blur !== undefined) font.blur = tag.blur; 838 | } 839 | 840 | upscale(x: number, firstcomp: number, secondcomp: number) { 841 | return (ruleOfThree(firstcomp, secondcomp) * x) / 100; 842 | } 843 | 844 | fontDecriptorString(font: StyleDescriptor) { 845 | return `${font.bold ? 'bold ' : ''}${font.italic ? 'italic ' : ''}${font.fontsize.toFixed( 846 | 3 847 | )}px "${font.fontname}"`; 848 | } 849 | 850 | computeStyle(name: string, alignment: number, layer: Layer): StyleDescriptor { 851 | const style = this.styles[name] as CompiledASSStyle; 852 | if (style === undefined) { 853 | // TODO: fallbackFont when there is no style 854 | // Fallbacks most of the time to Arial 855 | this.log('WARN', `[ass-html5:renderer] no corresponding style "${name}" found`); 856 | } 857 | const { 858 | fn, // font name 859 | fs, // font size 860 | a1, // primary alpha 861 | a2, // secondary alpha 862 | a3, // outline alpha 863 | c4, // shadow color 864 | a4, // shadow alpha 865 | b, // bold 866 | i, // italic 867 | u, // underline 868 | s, // strikeout 869 | fscx, // font scale x 870 | fscy, // font scale y 871 | fsp, // font spacing 872 | frz, // font rotation z 873 | xbord, // x border 874 | ybord, // y border 875 | xshad, // x shadow 876 | yshad, // y shadow 877 | fe, // font encoding 878 | q // wrap style 879 | } = style.tag; 880 | 881 | const { PrimaryColour, OutlineColour, SecondaryColour, BorderStyle } = style.style; 882 | 883 | const font: StyleDescriptor = { 884 | fontsize: this.upscale(fs, this.playerResY, this.layers[0]?.canvas.height || this.playerResY), 885 | fontname: fn, 886 | bold: b === 1, 887 | italic: i === 1, 888 | underline: u === 1, 889 | strikeout: s === 1, 890 | colors: { 891 | c1: convertAegisubColorToHex(PrimaryColour), 892 | c2: convertAegisubColorToHex(SecondaryColour), 893 | c3: convertAegisubColorToHex(OutlineColour), 894 | c4, 895 | a1: parseAlpha(a1), 896 | a2: parseAlpha(a2), 897 | a3: parseAlpha(a3), 898 | a4: parseAlpha(a4) 899 | }, 900 | t: { 901 | fscx: fscx, 902 | fscy: fscy, 903 | frz: frz, 904 | frx: 0, 905 | fry: 0, 906 | fsp: this.upscale(fsp, this.playerResX, layer.canvas.width), 907 | q: q 908 | }, 909 | customAnimations: [], 910 | xbord: xbord, 911 | ybord: ybord, 912 | xshad: xshad, 913 | yshad: yshad, 914 | blur: 0, 915 | fe: fe, 916 | borderStyle: BorderStyle, 917 | opacity: 1, 918 | textAlign: this.getAlignment(alignment), 919 | textBaseline: this.getBaseLine(alignment) 920 | }; 921 | 922 | this.applyFont(font, layer); 923 | 924 | return font; 925 | } 926 | 927 | applyFont(font: StyleDescriptor, layer: Layer) { 928 | layer.ctx.font = this.fontDecriptorString(font); 929 | layer.ctx.fillStyle = blendAlpha(font.colors.c1, font.colors.a1); 930 | layer.ctx.strokeStyle = blendAlpha(font.colors.c3, font.colors.a3); 931 | layer.ctx.letterSpacing = `${font.t.fsp}px`; 932 | layer.ctx.shadowOffsetX = this.upscale( 933 | font.xshad, 934 | this.playerResX, 935 | this.layers[0]?.canvas.width || this.playerResX 936 | ); 937 | layer.ctx.shadowOffsetY = this.upscale( 938 | font.yshad, 939 | this.playerResY, 940 | this.layers[0]?.canvas.height || this.playerResY 941 | ); 942 | layer.ctx.shadowBlur = this.upscale( 943 | font.blur, 944 | this.playerResY, 945 | this.layers[0]?.canvas.height || this.playerResY 946 | ); 947 | layer.ctx.shadowColor = blendAlpha(font.colors.c4, font.colors.a4); 948 | layer.ctx.lineWidth = 949 | this.upscale(font.xbord, this.playerResX, this.layers[0]?.canvas.width || this.playerResX) + 950 | this.upscale(font.ybord, this.playerResY, this.layers[0]?.canvas.height || this.playerResY); 951 | layer.ctx.lineCap = 'round'; 952 | layer.ctx.lineJoin = 'round'; 953 | layer.ctx.globalAlpha = font.opacity; 954 | } 955 | 956 | getAlignment(alignment: number) { 957 | // 1 = (bottom) left 958 | // 2 = (bottom) center 959 | // 3 = (bottom) right 960 | // 4 = (middle) left 961 | // 5 = (middle) center 962 | // 6 = (middle) right 963 | // 7 = (top) left 964 | // 8 = (top) center 965 | // 9 = (top) right 966 | switch (alignment) { 967 | case 1: 968 | case 4: 969 | case 7: 970 | return Align.Left; 971 | case 2: 972 | case 5: 973 | case 8: 974 | return Align.Center; 975 | case 3: 976 | case 6: 977 | case 9: 978 | return Align.Right; 979 | default: 980 | return Align.Start; 981 | } 982 | } 983 | 984 | getBaseLine(alignment: number) { 985 | // 1 = (bottom) left 986 | // 2 = (bottom) center 987 | // 3 = (bottom) right 988 | // 4 = (middle) left 989 | // 5 = (middle) center 990 | // 6 = (middle) right 991 | // 7 = (top) left 992 | // 8 = (top) center 993 | // 9 = (top) right 994 | switch (alignment) { 995 | case 1: 996 | case 2: 997 | case 3: 998 | return Baseline.Bottom; 999 | case 4: 1000 | case 5: 1001 | case 6: 1002 | return Baseline.Middle; 1003 | case 7: 1004 | case 8: 1005 | case 9: 1006 | return Baseline.Top; 1007 | default: 1008 | return Baseline.Alphabetic; 1009 | } 1010 | } 1011 | } 1012 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { CompiledASSStyle, Dialogue } from 'ass-compiler'; 2 | import type { CompiledTag, ParsedTag } from 'ass-compiler/types/tags'; 3 | import { Vector2 } from './utils'; 4 | 5 | export type OnInitSizes = { 6 | width: number; 7 | height: number; 8 | x: number; 9 | y: number; 10 | }; 11 | 12 | export enum Baseline { 13 | Bottom, 14 | Middle, 15 | Top, 16 | Alphabetic 17 | } 18 | 19 | export enum Align { 20 | Left, 21 | Center, 22 | Right, 23 | Start 24 | } 25 | 26 | export type CustomAnimation = { 27 | t1: number; 28 | t2: number; 29 | accel: number; 30 | tag: CompiledTag; 31 | }; 32 | 33 | export type StyleDescriptor = { 34 | fontname: string; 35 | fontsize: number; 36 | bold: boolean; 37 | italic: boolean; 38 | underline: boolean; 39 | strikeout: boolean; 40 | colors: Colors; 41 | /** font transformation */ 42 | t: FontTransfomation; 43 | customAnimations: CustomAnimation[]; 44 | /** x border */ 45 | xbord: number; 46 | /** y border */ 47 | ybord: number; 48 | xshad: number; 49 | yshad: number; 50 | /** shadow blur */ 51 | blur: number; 52 | /** font encoding */ 53 | fe?: number; 54 | borderStyle: number; 55 | opacity: number; 56 | textAlign: Align; 57 | textBaseline: Baseline; 58 | }; 59 | 60 | export type Layer = { 61 | canvas: HTMLCanvasElement; 62 | ctx: CanvasRenderingContext2D; 63 | }; 64 | 65 | export type Colors = { 66 | c1: string; 67 | a1: number; 68 | c2: string; 69 | a2: number; 70 | c3: string; 71 | a3: number; 72 | c4: string; 73 | a4: number; 74 | }; 75 | 76 | export type FontTransfomation = { 77 | /** font scale x */ 78 | fscx: number; 79 | /** font scale y */ 80 | fscy: number; 81 | /** font rotation z*/ 82 | frz: number; 83 | /** font rotation x*/ 84 | frx: number; 85 | /** font rotation y*/ 86 | fry: number; 87 | /** font shear x */ 88 | fax?: number; 89 | /** font shear y */ 90 | fay?: number; 91 | /** font spacing */ 92 | fsp: number; 93 | /** wrap style */ 94 | q: 0 | 2 | 1 | 3; 95 | }; 96 | 97 | export type Tag = { [K in keyof ParsedTag]: ParsedTag[K] }; 98 | 99 | export type Override = { 100 | dialogue: Dialogue; 101 | style: CompiledASSStyle; 102 | }; 103 | 104 | export type Styles = { [styleName: string]: CompiledASSStyle }; 105 | 106 | export type Position = { 107 | x: number; 108 | y: number; 109 | }; 110 | 111 | export type LOGTYPE = 'DISABLE' | 'VERBOSE' | 'DEBUG' | 'WARN'; 112 | 113 | export enum CHARKIND { 114 | NEWLINE, 115 | NORMAL 116 | } 117 | 118 | export type Margin = { left: number; right: number; vertical: number }; 119 | export type Char = 120 | | { 121 | kind: CHARKIND.NORMAL; 122 | pos: Vector2; 123 | c: string; 124 | w: number; 125 | tag: CompiledTag; 126 | style: string; 127 | ord: number; 128 | } 129 | | { 130 | kind: CHARKIND.NEWLINE; 131 | }; 132 | 133 | export type Word = { 134 | w: number; 135 | font: StyleDescriptor; 136 | value: Char[]; 137 | }; 138 | 139 | export enum FadeKind { 140 | Simple, 141 | Complex 142 | } 143 | export type FadeAnimation = 144 | | { 145 | type: FadeKind.Simple; 146 | fadein: number; 147 | fadeout: number; 148 | } 149 | | { 150 | type: FadeKind.Complex; 151 | a1: number; 152 | a2: number; 153 | a3: number; 154 | t1: number; 155 | t2: number; 156 | t3: number; 157 | t4: number; 158 | }; 159 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | import { type Tag, type Char, CHARKIND, FadeAnimation, FadeKind } from './types'; 2 | /** 3 | * Convert a color in RGBA format to Aegisub format 4 | * @param aegisubColor The color in Aegisub format 5 | * @returns The color in RGBA format 6 | */ 7 | export function convertAegisubColorToHex(aegisubColor: string) { 8 | const colorValue = aegisubColor.replace(/&H|&/g, ''); 9 | 10 | // Extract the individual color components from the Aegisub color value 11 | const blue = parseInt(colorValue.slice(2, 4), 16); 12 | const green = parseInt(colorValue.slice(4, 6), 16); 13 | const red = parseInt(colorValue.slice(6, 8), 16); 14 | 15 | // Create the RGBA 16 | const rgba = `rgb(${red}, ${green}, ${blue}, 1)`; 17 | const hex = rgbaToHex(rgba); 18 | return hex; 19 | } 20 | 21 | export function swapBBGGRR(color: string) { 22 | // color : #FF0008 -> #0800FF 23 | const colorValue = color.replace('#', ''); 24 | const blue = colorValue.slice(0, 2); 25 | const green = colorValue.slice(2, 4); 26 | const red = colorValue.slice(4, 6); 27 | return `#${red}${green}${blue}`; 28 | } 29 | 30 | export function changeAlpha(color: string, alpha: number) { 31 | if (color.startsWith('rgba')) { 32 | return color.replace(/rgba\((\d+), (\d+), (\d+), (\d+)\)/, `rgba($1, $2, $3, ${alpha})`); 33 | } else { 34 | // hexToRgba 35 | const rgba = hexToRgba(color); 36 | return rgba.replace(/rgba\((\d+), (\d+), (\d+), (\d+)\)/, `rgba($1, $2, $3, ${alpha})`); 37 | } 38 | } 39 | 40 | export function getAlphaFromColor(color: string) { 41 | if (color.startsWith('rgba')) { 42 | const alpha = color.replace(/rgba\((\d+), (\d+), (\d+), (\d+)\)/, '$4'); 43 | // console.debug(color, "getAlphaFromColor", "rgba") 44 | return parseFloat(alpha); 45 | } else { 46 | // hexToRgba 47 | const rgba = hexToRgba(color); 48 | // console.debug(rgba, "getAlphaFromColor", "hex") 49 | return parseFloat(rgba.replace(/rgba\((\d+), (\d+), (\d+), (\d+)\)/, '$4')); 50 | } 51 | } 52 | 53 | export function rgbaToHex(rgba: string) { 54 | const components = rgba.match(/\d+/g) as string[]; // Extract numeric values from RGBA string 55 | let red = parseInt(components[0] as string); 56 | let green = parseInt(components[1] as string); 57 | let blue = parseInt(components[2] as string); 58 | let alpha = parseFloat(components[3] as string); 59 | 60 | let redHex = red.toString(16).padStart(2, '0'); 61 | let greenHex = green.toString(16).padStart(2, '0'); 62 | let blueHex = blue.toString(16).padStart(2, '0'); 63 | 64 | let rgbHex = '#' + redHex + greenHex + blueHex; 65 | 66 | if (alpha !== 1) { 67 | let alphaHex = Math.round(alpha * 255) 68 | .toString(16) 69 | .padStart(2, '0'); 70 | return rgbHex + alphaHex; 71 | } 72 | 73 | return rgbHex; 74 | } 75 | 76 | export function hexToRgba(hex: string, defaultAlpha = 1) { 77 | const hexValue = hex.replace('#', ''); // Remove '#' if present 78 | const isShortHex = hexValue.length === 3 || hexValue.length === 4; 79 | 80 | let redHex, greenHex, blueHex, alphaHex; 81 | if (isShortHex) { 82 | redHex = (hexValue[0] as string) + (hexValue[0] as string); 83 | greenHex = (hexValue[1] as string) + (hexValue[1] as string); 84 | blueHex = (hexValue[2] as string) + (hexValue[2] as string); 85 | if (hexValue.length === 4) { 86 | alphaHex = (hexValue[3] as string) + (hexValue[3] as string); 87 | } else { 88 | alphaHex = 'FF'; // Default alpha value if not provided 89 | } 90 | } else { 91 | redHex = hexValue.substring(0, 2); 92 | greenHex = hexValue.substring(2, 4); 93 | blueHex = hexValue.substring(4, 6); 94 | if (hexValue.length === 8) { 95 | alphaHex = hexValue.substring(6, 8); 96 | } else { 97 | alphaHex = 'FF'; // Default alpha value if not provided 98 | } 99 | } 100 | 101 | const red = parseInt(redHex, 16); 102 | const green = parseInt(greenHex, 16); 103 | const blue = parseInt(blueHex, 16); 104 | const alpha = parseInt(alphaHex, 16) / 255; 105 | 106 | return 'rgba(' + red + ', ' + green + ', ' + blue + ', ' + alpha + ')'; 107 | } 108 | 109 | export function insertTags(tags: Tag[], tag: Tag) { 110 | tags.forEach((singleTag) => { 111 | // if the tag is already present, it will be overwritten 112 | tag = { ...tag, ...singleTag }; 113 | }); 114 | return tag; 115 | } 116 | 117 | export function ruleOfThree(value: number, valueMin: number) { 118 | return (valueMin * 100) / value; 119 | } 120 | 121 | export function genRandomString(ln: number) { 122 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 123 | let randomString = ''; 124 | 125 | for (let i = 0; i < ln; i++) { 126 | const randomIndex = Math.floor(Math.random() * characters.length); 127 | randomString += characters.charAt(randomIndex); 128 | } 129 | 130 | return randomString; 131 | } 132 | 133 | export function randomId(parts: number, separator = '-', prefix = '', ln = 10) { 134 | let partsArray: string[] = []; 135 | for (let i = 0; i < parts; i++) { 136 | partsArray.push(genRandomString(ln)); 137 | } 138 | return prefix + partsArray.join(separator); 139 | } 140 | 141 | export function stringHash(str: string) { 142 | let hash = 0; 143 | 144 | if (str.length == 0) return hash; 145 | 146 | for (let i = 0; i < str.length; i++) { 147 | let char = str.charCodeAt(i); 148 | hash = (hash << 5) - hash + char; 149 | hash = hash & hash; 150 | } 151 | 152 | return hash; 153 | } 154 | 155 | export function chunkCharWidth(chars: Char[]) { 156 | let w = 0; 157 | for (let i = 0; i < chars.length; i++) { 158 | let char = chars[i] as Char; 159 | if (char.kind == CHARKIND.NORMAL) { 160 | w += char.w; 161 | } 162 | } 163 | 164 | return w; 165 | } 166 | 167 | export function chunkCharToString(chars: Char[]) { 168 | let w = ''; 169 | for (let i = 0; i < chars.length; i++) { 170 | let char = chars[i] as Char; 171 | if (char.kind == CHARKIND.NORMAL) { 172 | w += char.c; 173 | } 174 | } 175 | 176 | return w; 177 | } 178 | 179 | export function newRender( 180 | top: number, 181 | left: number, 182 | width: number, 183 | height: number, 184 | zIndex?: number, 185 | insertAfter?: HTMLElement 186 | ) { 187 | const render = document.createElement('div'); 188 | render.id = randomId(2, '-', 'ASSRendererRender-', 5); 189 | render.style.position = 'absolute'; 190 | render.style.width = width + 'px'; 191 | render.style.height = height + 'px'; 192 | render.style.top = top + 'px'; 193 | render.style.left = left + 'px'; 194 | render.style.pointerEvents = 'none'; 195 | render.style.overflow = 'hidden'; 196 | render.style.boxSizing = 'border-box'; 197 | render.style.padding = '0px'; 198 | render.style.margin = '0px'; 199 | if (zIndex) { 200 | render.style.zIndex = zIndex.toString(); 201 | } 202 | 203 | if (insertAfter) { 204 | insertAfter.after(render); 205 | } else { 206 | document.body.appendChild(render); 207 | } 208 | 209 | return render; 210 | } 211 | 212 | export function newCanvas( 213 | width: number, 214 | height: number, 215 | dataLayer = 0, 216 | layerName?: string, 217 | appendIn?: HTMLElement, 218 | insertAfter?: HTMLElement 219 | ) { 220 | const canvas = document.createElement('canvas'); 221 | canvas.id = randomId(2, '-', 'Canvas-', 5); 222 | canvas.style.position = 'absolute'; 223 | canvas.style.top = '0px'; 224 | canvas.style.left = '0px'; 225 | canvas.style.pointerEvents = 'none'; 226 | canvas.width = width; 227 | canvas.height = height; 228 | canvas.dataset.layer = dataLayer.toString(); 229 | canvas.dataset.identifier = uuidgen(); 230 | 231 | if (layerName) { 232 | canvas.dataset.name = layerName; 233 | } 234 | 235 | if (insertAfter) { 236 | insertAfter.after(canvas); 237 | } else { 238 | if (!appendIn) { 239 | appendIn = document.body; 240 | } 241 | appendIn.appendChild(canvas); 242 | } 243 | return canvas; 244 | } 245 | 246 | export function uuidgen() { 247 | const v4 = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'; 248 | return v4.replace(/[xy]/g, (c) => { 249 | const r = (Math.random() * 16) | 0; 250 | const v = c === 'x' ? r : (r & 0x3) | 0x8; 251 | return v.toString(16); 252 | }); 253 | } 254 | 255 | export function parseAlpha(of: string) { 256 | const a = `0x${of}`; 257 | return parseInt(a, 16); 258 | } 259 | 260 | export function blendAlpha(color: string, alpha: number) { 261 | color = color.replace('#', ''); 262 | // color = FFFFFF 263 | // alpha = 0x80 264 | // return rgba(255, 255, 255, 0.5) 265 | const red = parseInt(color.substring(0, 2), 16); 266 | const green = parseInt(color.substring(2, 4), 16); 267 | const blue = parseInt(color.substring(4, 6), 16); 268 | return `rgba(${red}, ${green}, ${blue}, ${alpha == 0 ? 1 : alpha / 255})`; 269 | } 270 | 271 | export class Vector2 { 272 | x: number; 273 | y: number; 274 | constructor(x: number = 0, y: number = 0) { 275 | this.x = x; 276 | this.y = y; 277 | } 278 | 279 | add(rhs: Vector2): Vector2 { 280 | return new Vector2(this.x + rhs.x, this.y + rhs.y); 281 | } 282 | sub(rhs: Vector2): Vector2 { 283 | return new Vector2(this.x - rhs.x, this.y - rhs.y); 284 | } 285 | mul(i: number): Vector2 { 286 | return new Vector2(this.x * i, this.y * i); 287 | } 288 | } 289 | 290 | /** 291 | * Interpolate a vector2 between tow vector2 292 | * @param start - starting point 293 | * @param end - the end point 294 | * @param t a value between 0 and 1 295 | * @returns A new Vector2 representing the interpolated point 296 | */ 297 | export function vectorLerp(start: Vector2, end: Vector2, t: number): Vector2 { 298 | // start + (end - start) * t 299 | return start.add(end.sub(start).mul(t)); 300 | } 301 | 302 | export function lerp(start: number, end: number, t: number): number { 303 | return start + (end - start) * t; 304 | } 305 | 306 | /** 307 | * Produce a fade-in and fade-out effect. The fadein and fadeout times are 308 | * given in milliseconds, ie. 1000 means one second. You can specify fadein or 309 | * fadeout as 0 (zero) to not have any fade effect on that end. 310 | */ 311 | export function getOpacity( 312 | fade: Extract, 313 | startTime: number, 314 | endTime: number, 315 | time: number 316 | ): number { 317 | const fadeIn = startTime + fade.fadein; 318 | const fadeOut = endTime - fade.fadeout; 319 | if (time < fadeIn) { 320 | let t = (time - startTime) / (fadeIn - startTime); 321 | return lerp(0, 1, t); 322 | } else if (time >= fadeIn && time < fadeOut) { 323 | return 1; 324 | } else if (time >= fadeOut && time <= endTime) { 325 | let t = (time - fadeOut) / (endTime - fadeOut); 326 | return lerp(1, 0, t); 327 | } else { 328 | return -1; 329 | } 330 | } 331 | 332 | /** 333 | * Perform a five-part fade using three alpha values a1, a2 and a3 and four 334 | * times t1, t2, t3 and t4. 335 | * 336 | * The alpha values are given in decimal and are between 0 and 255, with 0 337 | * being fully visible and 255 being invisible. The time values are given in 338 | * milliseconds after the start of the line. All seven parameters are 339 | * required. (For most common fade effects the `\fad` tag works fine.) 340 | * 341 | * - Before t1, the line has alpha a1. 342 | * - Between t1 and t2 the line fades from alpha a1 to alpha a2. 343 | * - Between t2 and t3 the line has alpha a2 constantly. 344 | * - Between t3 and t4 the line fades from alpha a2 to alpha a3. 345 | * - After t4 the line has alpha a3. 346 | */ 347 | export function getOpacityComplex( 348 | fade: Extract, 349 | startTime: number, 350 | endTime: number, 351 | time: number 352 | ): number { 353 | console.debug(fade); 354 | 355 | const t1 = startTime + fade.t1; 356 | const t2 = startTime + fade.t2; 357 | const t3 = startTime + fade.t3; 358 | const t4 = startTime + fade.t4; 359 | 360 | if (time < t1) { 361 | return fade.a1; 362 | } else if (time >= t1 && time < t2) { 363 | let t = (time - t1) / (t2 - t1); 364 | return lerp(fade.a1, fade.a2, t); 365 | } else if (time >= t2 && time < t3) { 366 | return fade.a2; 367 | } else if (time >= t3 && time < t4) { 368 | let t = (time - t3) / (t4 - t3); 369 | return lerp(fade.a2, fade.a3, t); 370 | } else if (time >= t4 && time <= endTime) { 371 | return fade.a3; 372 | } else { 373 | return -1; 374 | } 375 | } 376 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, 4 | "module": "esnext" /* Specify what module code is generated. */, 5 | "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, 6 | "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, 7 | "strict": true /* Enable all strict type-checking options. */, 8 | "skipLibCheck": true /* Skip type checking all .d.ts files. */, 9 | "noUncheckedIndexedAccess": true, 10 | "noEmit": true, 11 | "removeComments": true, 12 | "lib": ["esnext", "dom"], 13 | "moduleResolution": "node" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | 3 | export default defineConfig({ 4 | entry: ['src/ass.ts'], 5 | clean: false, 6 | dts: true, 7 | platform: 'browser', 8 | target: 'esnext', 9 | noExternal: ['ass-compiler'], 10 | name: 'ASS', 11 | globalName: 'ass', 12 | format: ['esm', 'cjs'], 13 | async onSuccess() { 14 | console.log(' END ' + Date().split(' ')[4]); 15 | } 16 | }); 17 | --------------------------------------------------------------------------------