UNPKG

assjs

Version:

A lightweight JavaScript ASS subtitle renderer

186 lines (180 loc) 4.92 kB
.ASS-box { font-family: Arial; overflow: hidden; pointer-events: none; position: absolute; } .ASS-dialogue { font-size: 0; width: max-content; position: absolute; z-index: 0; transform: translate(calc(var(--ass-align-h) * -1), calc(var(--ass-align-v) * -1)); span { display: inline-block; } [data-text] { display: inline-block; color: var(--ass-fill-color); font-size: calc(var(--ass-scale) * var(--ass-real-fs) * 1px); line-height: calc(var(--ass-scale) * var(--ass-tag-fs) * 1px); letter-spacing: calc(var(--ass-scale) * var(--ass-tag-fsp) * 1px); /* for \bord0\blur4 */ /* when x > 0, round(up, sin(x) * sin(x)) === sign(x) */ /* sign() requires higher browser version */ filter: blur(calc( var(--ass-scale-stroke) * var(--ass-tag-blur) * (1 - round(up, sin(var(--ass-tag-xbord)) * sin(var(--ass-tag-xbord)))) * (1 - round(up, sin(var(--ass-tag-ybord)) * sin(var(--ass-tag-ybord)))) * 1px )); } [data-is="br"] + [data-is="br"] { height: calc(var(--ass-scale) * var(--ass-tag-fs) * 1px / 2); } } .ASS-dialogue[data-wrap-style="0"], .ASS-dialogue[data-wrap-style="3"] { /* \q3 is just treated the same as \q0 in libass */ text-wrap: balance; white-space: pre-wrap; } .ASS-dialogue[data-wrap-style="1"] { word-break: break-word; white-space: pre-wrap; } .ASS-dialogue[data-wrap-style="2"] { word-break: normal; white-space: pre; } .ASS-dialogue [data-border-style="1"] { position: relative; &::before, &::after { content: attr(data-text); position: absolute; top: 0; left: 0; z-index: -1; filter: blur(calc(var(--ass-scale-stroke) * var(--ass-tag-blur) * 1px)); } &::before { color: var(--ass-shadow-color); -webkit-text-stroke: calc(var(--ass-scale-stroke) * var(--ass-border-width) * 1px) var(--ass-shadow-color); transform: translate(calc(var(--ass-scale-stroke) * var(--ass-tag-xshad) * 1px), calc(var(--ass-scale-stroke) * var(--ass-tag-yshad) * 1px)); } &::after { color: var(--ass-border-color); -webkit-text-stroke: calc(var(--ass-scale-stroke) * var(--ass-border-width) * 1px) var(--ass-border-color); } &[data-stroke="svg"] { color: #000; &::before, &::after { opacity: 0; } } } @container style(--ass-tag-xbord: 0) and style(--ass-tag-ybord: 0) { .ASS-dialogue [data-border-style="1"]::after { display: none; } } @container style(--ass-tag-xshad: 0) and style(--ass-tag-yshad: 0) { .ASS-dialogue [data-border-style="1"]::before { display: none; } } .ASS-dialogue [data-border-style="3"] { padding: calc(var(--ass-scale-stroke) * var(--ass-tag-xbord) * 1px) calc(var(--ass-scale-stroke) * var(--ass-tag-ybord) * 1px); position: relative; filter: blur(calc(var(--ass-scale-stroke) * var(--ass-tag-blur) * 1px)); &::before, &::after { content: ""; width: 100%; height: 100%; position: absolute; z-index: -1; } &::before { background-color: var(--ass-shadow-color); left: calc(var(--ass-scale-stroke) * var(--ass-tag-xshad) * 1px); top: calc(var(--ass-scale-stroke) * var(--ass-tag-yshad) * 1px); } &::after { background-color: var(--ass-border-color); left: 0; top: 0; } } @container style(--ass-tag-xbord: 0) and style(--ass-tag-ybord: 0) { .ASS-dialogue [data-border-style="3"]::after { background-color: transparent; } } @container style(--ass-tag-xshad: 0) and style(--ass-tag-yshad: 0) { .ASS-dialogue [data-border-style="3"]::before { background-color: transparent; } } .ASS-dialogue [data-rotate] { /* TODO: {\an5\fs80\bord0\shad60\frx30\frz30\fry30}1234567890 */ /* TODO: {\frz-90\shad30} */ /* https://github.com/libass/libass/issues/805 */ transform: perspective(312.5px) rotateY(calc(var(--ass-tag-fry) * 1deg)) rotateX(calc(var(--ass-tag-frx) * 1deg)) rotateZ(calc(var(--ass-tag-frz) * -1deg)); &[data-text] { transform-style: preserve-3d; word-break: normal; white-space: nowrap; } } .ASS-dialogue [data-scale], .ASS-dialogue [data-skew] { display: inline-block; transform: scale(var(--ass-tag-fscx), var(--ass-tag-fscy)) skew(calc(var(--ass-tag-fax) * 1rad), calc(var(--ass-tag-fay) * 1rad)); transform-origin: var(--ass-align-h) var(--ass-align-v); } .ASS-fix-font-size { font-family: Arial; line-height: normal; width: 0; height: 0; position: absolute; visibility: hidden; overflow: hidden; span { position: absolute; } } .ASS-clip-area { width: 100%; height: 100%; position: absolute; top: 0; left: 0; } .ASS-effect-area { position: absolute; display: flex; width: 100%; height: fit-content; overflow: hidden; mask-composite: intersect; &[data-effect="banner"] { flex-direction: column; height: 100%; } .ASS-dialogue { position: static; transform: none; } }