@phont-ai/subtitles-core 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -83,6 +83,8 @@ interface AnimationParameterState {
83
83
  textColor: string;
84
84
  opacity: number;
85
85
  textShadow: string;
86
+ shadowX?: number;
87
+ shadowY?: number;
86
88
  blur: number;
87
89
  outlineWidth: number;
88
90
  outlineColor: string;
package/dist/browser.d.ts CHANGED
@@ -83,6 +83,8 @@ interface AnimationParameterState {
83
83
  textColor: string;
84
84
  opacity: number;
85
85
  textShadow: string;
86
+ shadowX?: number;
87
+ shadowY?: number;
86
88
  blur: number;
87
89
  outlineWidth: number;
88
90
  outlineColor: string;
package/dist/browser.js CHANGED
@@ -1 +1 @@
1
- "use strict";var it=Object.defineProperty;var Ft=Object.getOwnPropertyDescriptor;var Pt=Object.getOwnPropertyNames;var Ht=Object.prototype.hasOwnProperty;var It=(t,e)=>{for(var n in e)it(t,n,{get:e[n],enumerable:!0})},Rt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Pt(e))!Ht.call(t,i)&&i!==n&&it(t,i,{get:()=>e[i],enumerable:!(r=Ft(e,i))||r.enumerable});return t};var Nt=t=>Rt(it({},"__esModule",{value:!0}),t);var Dt={};It(Dt,{attach:()=>vt,decodeAnimationUrl:()=>K,loadMetadataTrack:()=>Tt,sampleAt:()=>tt,version:()=>Xt});module.exports=Nt(Dt);function jt(t,e=!1){if(!t)return[];try{return t.split("|").map(n=>{let[r,i]=n.split(","),o=e||typeof i=="string"&&(i.startsWith("#")||i.startsWith("%23")),s;return o?s=i.replace(/%23/g,"#"):s=parseFloat(i),{time:parseFloat(r),value:s}})}catch(n){return console.error("Error decoding points:",n),[]}}function zt(t){if(!t)return"";if(t.includes("://"))try{let e=new URL(t);return e.search.startsWith("?")?e.search.slice(1):e.search}catch{let e=t.indexOf("?");return e!==-1?t.substring(e+1):t}return t.startsWith("?")?t.slice(1):t}function K(t){try{let e=zt(t),n=new URLSearchParams(e),r={parameterStates:{}};if(n.has("name")&&(r.name=n.get("name")||void 0),n.has("user")&&(r.userName=n.get("user")||void 0),n.has("duration")&&(r.duration=parseFloat(n.get("duration")||"0")),n.has("mode")&&(r.animationMode=n.get("mode")||void 0),n.has("text")&&(r.text=n.get("text")||void 0),n.get("format")==="normalized"&&(r.format="normalized"),n.has("font"))try{let o=JSON.parse(n.get("font")||"{}");o&&typeof o=="object"&&(o.style||o.config||o.fontId?r.fontData={style:o.style,config:o.config||null,fontId:o.fontId||null,fontName:o.fontName||null}:r.fontData={style:o,config:null})}catch(o){console.warn("Failed to parse font data:",o)}if(n.has("bg"))try{r.backgroundStyle=JSON.parse(n.get("bg")||"{}")}catch(o){console.warn("Failed to parse background style:",o)}for(let[o,s]of n.entries())if(!["name","user","duration","mode","text","font","bg","v","c","m","p","format"].includes(o)&&(s.includes("|")||s.includes(","))){let l=o==="color"||o==="shadowColor"||o==="outlineColor"||s.includes("%23"),f=jt(s,l);if(f.length>0){let m=l?"#000000":0;r.parameterStates[o]={points:f,currentValue:f[0]?.value||m}}}return r}catch(e){throw console.error("Error decoding animation URL:",e),new Error("Failed to decode animation URL. The link may be invalid or corrupted.")}}function Q(t){if(typeof t!="string")return{r:0,g:0,b:0};let e=t.replace("#","").padStart(6,"0"),n=/^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:{r:0,g:0,b:0}}function ft(t,e,n){let r=i=>{let o=Math.round(Math.max(0,Math.min(255,i))).toString(16);return o.length===1?"0"+o:o};return"#"+r(t)+r(e)+r(n)}function mt(t,e,n){let r=Q(t),i=Q(e),o=Math.max(0,Math.min(1,n)),s=r.r+(i.r-r.r)*o,l=r.g+(i.g-r.g)*o,f=r.b+(i.b-r.b)*o;return ft(s,l,f)}function Yt(t,e,n){if(n===0)return t;let r=Q(t),i=Q(e),o=r.r+(i.r-r.r)*n,s=r.g+(i.g-r.g)*n,l=r.b+(i.b-r.b)*n;return ft(o,s,l)}function Z(t,e,n,r=!1,i=null){if(!t||t.length===0)return null;let o=r?e:e*n,s=null,l=null;for(let f=0;f<t.length;f++){let m=t[f],c=m.time!==void 0?m.time:Array.isArray(m)?m[0]:0;if(c!==void 0&&c<=o&&(s=m),c!==void 0&&c>=o&&!l){l=m;break}}if(!s&&t[0])return(t[0].value!==void 0?t[0].value:Array.isArray(t[0])?t[0][1]:null)??null;if(!l&&s)return(s.value!==void 0?s.value:Array.isArray(s)?s[1]:null)??null;if(s&&l){let f=s.time!==void 0?s.time??0:Array.isArray(s)?s[0]:0,m=l.time!==void 0?l.time??0:Array.isArray(l)?l[0]:0,c=s.value!==void 0?s.value:Array.isArray(s)?s[1]:null,d=l.value!==void 0?l.value:Array.isArray(l)?l[1]:null;if(f===m||c===null||d===null)return c??null;let a=(o-f)/(m-f),y=i==="color"||i==="shadowColor"||i==="outlineColor"||i==="outline2Color"||i==="outline3Color"||i==="outlineShadowColor"||i==="glowColor";if(y&&(typeof c=="string"||typeof d=="string"))return mt(typeof c=="string"?c:"#000000",typeof d=="string"?d:"#000000",a);if(!y&&(typeof c=="string"||typeof d=="string")){let W=typeof c=="string"&&(c.startsWith("#")||/^[0-9a-f]{6}$/i.test(c)),C=typeof d=="string"&&(d.startsWith("#")||/^[0-9a-f]{6}$/i.test(d));if(W&&C){let E=c.startsWith("#")?c:`#${c}`,T=d.startsWith("#")?d:`#${d}`;return mt(E,T,a)}return d??null}return c+(d-c)*a}return null}var st=.7,Bt=.7;function tt(t,e,n,r,i=null,{rawMode:o=!1}={}){if(!t||!t.parameterStates)return null;let s=o?1:e*r/(st*Bt),l=t.duration||2,m=t.format==="normalized"?n:n*l,c=!0,d=t.parameterStates||{},a=(p,w,v=!0,M=null)=>{let dt=M??s,J=Z(d[p]?.points,m,l,c);return J==null?w:v?dt===0?w:w+(J-w)*dt:J},y=a("scale",1),W=a("skew",0),C=a("stretch",1),E=a("translateX",0),T=a("translateY",0),L=a("weight",500),$=a("width",100),I=(t.fontData||{}).style?.fontFamily||"Roboto Flex",V=t.text||"Hello",k=(p,w)=>{let v=Z(d[p]?.points,m,l,c,p);if(v==null)return w;let M=typeof v=="string"?v.startsWith("#")?v:`#${v}`:`#${Math.round(v).toString(16).padStart(6,"0")}`;return s===0?w:Yt(w,M,s)},O=k("color","#ffffff"),A=a("opacity",1),z=a("shadowX",0),u=a("shadowY",0),h=a("shadowBlur",4),g=a("shadowOpacity",.5),b=k("shadowColor","#000000"),R=a("outlineWidth",0),N=k("outlineColor","#000000"),x=p=>d[p]?.points?.length>0,X=x("stretchX")?a("stretchX",1):void 0,D=x("outline2Width")?a("outline2Width",0):void 0,j=x("outline2Color")?k("outline2Color","#000000"):void 0,_=x("outline3Width")?a("outline3Width",0):void 0,U=x("outline3Color")?k("outline3Color","#000000"):void 0,q=x("outlineShadowWidth")?a("outlineShadowWidth",0):void 0,F=x("outlineShadowColor")?k("outlineShadowColor","#000000"):void 0,Y=x("outlineShadowBlur")?a("outlineShadowBlur",0):void 0,P=x("glowIntensity")?a("glowIntensity",0):void 0,G=x("glowColor")?k("glowColor","#ffffff"):void 0,ut=x("snakeWave")?a("snakeWave",0):void 0,ct=x("karaoke")?a("karaoke",0):void 0,Ct=1-.5*Math.min(1,Math.max(0,r)),kt=a("blur",0,!0,o?1:s*Ct),nt=Z(d.thinStroke?.points,m,l,c),rt=Z(d.ascenderHeight?.points,m,l,c),B={};nt!=null&&typeof nt=="number"&&(B.YOPQ=nt),rt!=null&&typeof rt=="number"&&(B.YTAS=rt),L!=null&&(B.wght=L),$!=null&&(B.wdth=$);let H=[];if(z!==0||u!==0||h!==4||g!==.5){let p=typeof b=="string"?b:"#000000",w=parseInt(p.slice(1,3),16),v=parseInt(p.slice(3,5),16),M=parseInt(p.slice(5,7),16);H.push(`${z}px ${u}px ${h}px rgba(${w}, ${v}, ${M}, ${g})`)}else if(b&&typeof b=="string"&&b!=="#000000"){let p=b.startsWith("#")?b:`#${b}`,w=parseInt(p.slice(1,3),16)||0,v=parseInt(p.slice(3,5),16)||0,M=parseInt(p.slice(5,7),16)||0;H.push(`3px 2px 4px rgba(${w}, ${v}, ${M}, 0.5)`)}if(P!=null&&P>0){let p=typeof G=="string"?G:"#ffffff";H.push(`0 0 ${P}px ${p}`),H.push(`0 0 ${P*2}px ${p}`),H.push(`0 0 ${P*4}px ${p}`)}let Et=H.length>0?H.join(", "):"",ot=0;if(d.joy?.points&&d.joy.points.length>0)for(let p of d.joy.points){let w=Array.isArray(p)?p[1]:p.y??p.value??0;typeof w=="number"&&w>ot&&(ot=w)}let At=a("joy",0,!1),Mt=o?At:Math.min(1,ot*s),Wt=a("fear",0),Lt=a("standardEmphasis",0,!1),$t=a("strongEmphasis",0,!1),S={rawIntensity:e,scaleFactor:s,scale:y,slant:W,stretchY:C,translateX:E,translateY:T,weight:L,width:$,fontFamily:I,textColor:O,opacity:A,textShadow:Et,blur:kt,outlineWidth:R,outlineColor:N,letterSpacing:`${Math.max(0,(y-1)*.02)}em`,fontVariationAxes:B,text:V,joy:Mt,fear:Wt,standardEmphasis:Lt,strongEmphasis:$t,joyWaveProgress:m/l*1.5};return X!==void 0&&(S.stretchX=X),D!==void 0&&(S.outline2Width=D),j!==void 0&&(S.outline2Color=j),_!==void 0&&(S.outline3Width=_),U!==void 0&&(S.outline3Color=U),q!==void 0&&(S.outlineShadowWidth=q),F!==void 0&&(S.outlineShadowColor=F),Y!==void 0&&(S.outlineShadowBlur=Y),P!==void 0&&(S.glowIntensity=P),G!==void 0&&(S.glowColor=G),ut!==void 0&&(S.snakeWave=ut),ct!==void 0&&(S.karaoke=ct),S}var pt={},Vt={"Roboto Flex":"family=Roboto+Flex:opsz,wdth,wght,YOPQ,YTAS@8..144,25..151,100..1000,25..125,649..854&display=swap",Rakkas:"family=Rakkas&display=swap",Parkinsans:"family=Parkinsans:wght@300..800&display=swap","Bricolage Grotesque":"family=Bricolage+Grotesque:opsz,wdth,wght@12..96,75..100,200..800&display=swap",Cormorant:"family=Cormorant:wght@300..700&display=block"};function ht(t){if(!t)return;let e=t.replace(/["']/g,"").split(",")[0].trim();if(!e||e==="sans-serif"||e==="serif"||pt[e]||(pt[e]=!0,typeof document>"u"))return;let n=Vt[e],r=document.createElement("link");r.rel="stylesheet",r.href=n?`https://fonts.googleapis.com/css2?${n}`:`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e)}:wght@100..900&display=swap`,document.head.appendChild(r)}function at(t,e,n){let r=t.split(/\s+/).filter(Boolean);if(r.length===0)return[];let i=n-e,o=r.map(f=>f.length+1),s=o.reduce((f,m)=>f+m,0),l=e;return r.map((f,m)=>{let c=o[m]/s*i,d=Math.round(l*1e3)/1e3;return l+=c,{word:f,start:d,end:Math.round(l*1e3)/1e3}})}function gt(t){let e=t.parentElement;if(e&&e.classList.contains("phont-container"))return e;let n=document.createElement("div");return n.className="phont-container",n.style.cssText="position:relative;display:inline-block;width:100%;line-height:0;background:#000;",t.parentNode.insertBefore(n,t),n.appendChild(t),n}function yt(t){let e=document.createElement("div");return e.className="phont-subtitle-overlay",e.style.cssText="position:absolute;left:0;right:0;bottom:8%;display:flex;justify-content:center;align-items:center;pointer-events:none;z-index:10;padding:0 5%;box-sizing:border-box;",t.appendChild(e),e}function bt(t){let e=document.createElement("span");return e.className="phont-subtitle-text",e.style.cssText="display:inline-flex;flex-wrap:wrap;justify-content:center;align-items:baseline;gap:0;text-align:center;word-spacing:normal;",t.appendChild(e),e}function xt(){let t=document.createElement("style");return t.textContent=".phont-container video::-webkit-media-controls-fullscreen-button{display:none!important}.phont-container:fullscreen{background:#000}.phont-container:fullscreen video{width:100%;height:100%;object-fit:contain}",document.head.appendChild(t),t}function wt(t){let e=document.createElement("button");return e.className="phont-fs-btn",e.setAttribute("aria-label","Fullscreen"),e.innerHTML="&#x26F6;",e.style.cssText="position:absolute;top:12px;right:12px;z-index:20;background:rgba(0,0,0,0.55);border:none;color:#fff;font-size:18px;width:34px;height:34px;border-radius:6px;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s;pointer-events:auto;",t.appendChild(e),e}function lt(t,e){t.innerHTML="";let n=[];for(let r=0;r<e.length;r++){let i=document.createElement("span");i.className="phont-word",i.textContent=e[r].word,i.style.cssText="display:inline-block;white-space:pre;will-change:transform,opacity,margin;transform-origin:center bottom;transition:transform 60ms ease-out,opacity 60ms ease-out,filter 60ms ease-out,color 60ms ease-out,margin 60ms ease-out;",t.appendChild(i),n.push(i),r<e.length-1&&t.appendChild(document.createTextNode(" "))}return n}function Ot(t,e,n,r){t.style.fontSize=r,t.style.fontFamily=e.fontFamily,t.style.fontWeight=String(e.weight),t.style.fontStretch=`${e.width}%`,t.style.fontVariationSettings=`"wght" ${e.weight}, "wdth" ${e.width}`,t.style.color=e.textColor,t.style.transform=`skewX(${e.slant}deg) scaleX(${e.stretchX??1}) scaleY(${e.stretchY}) scale(${e.scale}) translate(${e.translateX}px,${e.translateY}px) translateZ(0)`,t.style.textShadow=e.textShadow||"none",t.style.filter=e.blur>0?`blur(${e.blur}px)`:"none",t.style.letterSpacing=e.letterSpacing,e.outlineWidth>0?(t.style.webkitTextStroke=`${e.outlineWidth}px ${e.outlineColor}`,t.style.paintOrder="stroke fill"):(t.style.webkitTextStroke="",t.style.paintOrder=""),t.style.opacity=String(n?e.opacity:Math.min(.25,e.opacity));let i=e.scale>1.01?(e.scale-1)*(t.textContent?.length||1)*.25:0,o=e.outlineWidth>0?e.outlineWidth*.02:0;t.style.marginLeft=i>0?`${i}em`:"",t.style.marginRight=`${.3+i+o}em`}function St(t,e,n){t.style.fontSize=n,t.style.opacity=e?"1":"0.25",t.style.color="#ffffff",t.style.transform="none",t.style.textShadow="1px 1px 3px rgba(0,0,0,0.7)",t.style.fontWeight="500",t.style.fontStretch="100%",t.style.fontVariationSettings='"wght" 500, "wdth" 100',t.style.filter="none",t.style.webkitTextStroke="",t.style.paintOrder="",t.style.letterSpacing="0em",t.style.marginLeft="",t.style.marginRight="0.3em"}function vt(t,e){let n=e||{},r=typeof t=="string"?document.querySelector(t):t;if(!r)return console.error("[PhontSubtitles] Video element not found:",t),null;let i=r,o=gt(i),s=xt(),l=wt(o),f=yt(o),m=bt(f);o.addEventListener("mouseenter",()=>{l.style.opacity="1"}),o.addEventListener("mouseleave",()=>{l.style.opacity="0"}),l.addEventListener("click",()=>{document.fullscreenElement||document.webkitFullscreenElement?(document.exitFullscreen||document.webkitExitFullscreen).call(document):(o.requestFullscreen||o.webkitRequestFullscreen).call(o)});function c(){let u=document.fullscreenElement||document.webkitFullscreenElement;l.innerHTML=u===o?"&#x2716;":"&#x26F6;"}document.addEventListener("fullscreenchange",c),document.addEventListener("webkitfullscreenchange",c);let d=null,a=null,y=null,W=.7,C=[],E=null,T=null,L=null;function $(){d=null,a=null,y=null,m.innerHTML="",m.style.opacity="0",C=[]}function et(){if(!d||!y||y.length===0){$();return}m.style.opacity="1";let u=i.currentTime,h=n.fontSize||"clamp(1.2rem, 3vw, 2.4rem)";for(let g=0;g<y.length;g++){let b=y[g],R=C[g];if(!R)continue;let N=b.start,x=b.end,X=Math.max(.01,x-N),D=Math.max(0,Math.min(1,(u-N)/X)),j=u>=N,_=u>=N&&u<x,U=u>=x;if(!a){St(R,j,h);continue}let q=b.gts!==void 0?b.gts:W,F;_?F=D:U?F=1:F=0;let Y=tt(a,st,F,q,null);if(!Y){St(R,j,h);continue}Ot(R,Y,j,h)}}function I(){let u=this;if(!u.activeCues||u.activeCues.length===0){$();return}let h=u.activeCues[0];try{let g=JSON.parse(h.text);if(d=h,g.words&&g.words.length>0?y=g.words:y=at(g.text||"",h.startTime,h.endTime),W=typeof g.gts=="number"?g.gts:.7,g.animation_url){a=K(g.animation_url);let b=a.fontData;ht(b?.style?.fontFamily??b?.fontName??null)}else a=null;C=lt(m,y)}catch{d=h,a=null,y=at(h.text||"",h.startTime,h.endTime),C=lt(m,y)}et()}function V(u){return u.kind!=="metadata"?!1:(u.mode="hidden",u.addEventListener("cuechange",I),T=u,!0)}function k(){if(!T||!T.activeCues)return;let u=T.activeCues;if(u.length===0){d&&$(),L=null;return}let h=u[0],g=`${h.startTime}_${h.endTime}`;g!==L&&(L=g,I.call(T))}function O(){k(),d&&et(),E=requestAnimationFrame(O)}let A=i.textTracks,z=!1;for(let u=0;u<A.length;u++)if(V(A[u])){z=!0;break}if(!z){let u=h=>{h.track&&h.track.kind==="metadata"&&(V(h.track),A.removeEventListener("addtrack",u))};A.addEventListener("addtrack",u)}return E=requestAnimationFrame(O),{overlay:f,wordsContainer:m,destroy(){E&&cancelAnimationFrame(E),T&&T.removeEventListener("cuechange",I);for(let u=0;u<A.length;u++)A[u].removeEventListener("cuechange",I);document.removeEventListener("fullscreenchange",c),document.removeEventListener("webkitfullscreenchange",c),s.parentNode&&s.remove(),l.remove(),f.remove()}}}function Tt(t,e){let n=document.createElement("track");return n.kind="metadata",n.src=e,n.default=!0,t.appendChild(n),n}var Xt="0.3.0";
1
+ "use strict";var it=Object.defineProperty;var $t=Object.getOwnPropertyDescriptor;var Pt=Object.getOwnPropertyNames;var Ht=Object.prototype.hasOwnProperty;var It=(t,e)=>{for(var n in e)it(t,n,{get:e[n],enumerable:!0})},Rt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Pt(e))!Ht.call(t,i)&&i!==n&&it(t,i,{get:()=>e[i],enumerable:!(r=$t(e,i))||r.enumerable});return t};var Nt=t=>Rt(it({},"__esModule",{value:!0}),t);var Dt={};It(Dt,{attach:()=>vt,decodeAnimationUrl:()=>K,loadMetadataTrack:()=>Tt,sampleAt:()=>tt,version:()=>Ot});module.exports=Nt(Dt);function jt(t,e=!1){if(!t)return[];try{return t.split("|").map(n=>{let[r,i]=n.split(","),o=e||typeof i=="string"&&(i.startsWith("#")||i.startsWith("%23")),s;return o?s=i.replace(/%23/g,"#"):s=parseFloat(i),{time:parseFloat(r),value:s}})}catch(n){return console.error("Error decoding points:",n),[]}}function Yt(t){if(!t)return"";if(t.includes("://"))try{let e=new URL(t);return e.search.startsWith("?")?e.search.slice(1):e.search}catch{let e=t.indexOf("?");return e!==-1?t.substring(e+1):t}return t.startsWith("?")?t.slice(1):t}function K(t){try{let e=Yt(t),n=new URLSearchParams(e),r={parameterStates:{}};if(n.has("name")&&(r.name=n.get("name")||void 0),n.has("user")&&(r.userName=n.get("user")||void 0),n.has("duration")&&(r.duration=parseFloat(n.get("duration")||"0")),n.has("mode")&&(r.animationMode=n.get("mode")||void 0),n.has("text")&&(r.text=n.get("text")||void 0),n.get("format")==="normalized"&&(r.format="normalized"),n.has("font"))try{let o=JSON.parse(n.get("font")||"{}");o&&typeof o=="object"&&(o.style||o.config||o.fontId?r.fontData={style:o.style,config:o.config||null,fontId:o.fontId||null,fontName:o.fontName||null}:r.fontData={style:o,config:null})}catch(o){console.warn("Failed to parse font data:",o)}if(n.has("bg"))try{r.backgroundStyle=JSON.parse(n.get("bg")||"{}")}catch(o){console.warn("Failed to parse background style:",o)}for(let[o,s]of n.entries())if(!["name","user","duration","mode","text","font","bg","v","c","m","p","format"].includes(o)&&(s.includes("|")||s.includes(","))){let l=o==="color"||o==="shadowColor"||o==="outlineColor"||s.includes("%23"),f=jt(s,l);if(f.length>0){let m=l?"#000000":0;r.parameterStates[o]={points:f,currentValue:f[0]?.value||m}}}return r}catch(e){throw console.error("Error decoding animation URL:",e),new Error("Failed to decode animation URL. The link may be invalid or corrupted.")}}function Q(t){if(typeof t!="string")return{r:0,g:0,b:0};let e=t.replace("#","").padStart(6,"0"),n=/^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:{r:0,g:0,b:0}}function ft(t,e,n){let r=i=>{let o=Math.round(Math.max(0,Math.min(255,i))).toString(16);return o.length===1?"0"+o:o};return"#"+r(t)+r(e)+r(n)}function mt(t,e,n){let r=Q(t),i=Q(e),o=Math.max(0,Math.min(1,n)),s=r.r+(i.r-r.r)*o,l=r.g+(i.g-r.g)*o,f=r.b+(i.b-r.b)*o;return ft(s,l,f)}function zt(t,e,n){if(n===0)return t;let r=Q(t),i=Q(e),o=r.r+(i.r-r.r)*n,s=r.g+(i.g-r.g)*n,l=r.b+(i.b-r.b)*n;return ft(o,s,l)}function Z(t,e,n,r=!1,i=null){if(!t||t.length===0)return null;let o=r?e:e*n,s=null,l=null;for(let f=0;f<t.length;f++){let m=t[f],c=m.time!==void 0?m.time:Array.isArray(m)?m[0]:0;if(c!==void 0&&c<=o&&(s=m),c!==void 0&&c>=o&&!l){l=m;break}}if(!s&&t[0])return(t[0].value!==void 0?t[0].value:Array.isArray(t[0])?t[0][1]:null)??null;if(!l&&s)return(s.value!==void 0?s.value:Array.isArray(s)?s[1]:null)??null;if(s&&l){let f=s.time!==void 0?s.time??0:Array.isArray(s)?s[0]:0,m=l.time!==void 0?l.time??0:Array.isArray(l)?l[0]:0,c=s.value!==void 0?s.value:Array.isArray(s)?s[1]:null,d=l.value!==void 0?l.value:Array.isArray(l)?l[1]:null;if(f===m||c===null||d===null)return c??null;let a=(o-f)/(m-f),y=i==="color"||i==="shadowColor"||i==="outlineColor"||i==="outline2Color"||i==="outline3Color"||i==="outlineShadowColor"||i==="glowColor";if(y&&(typeof c=="string"||typeof d=="string"))return mt(typeof c=="string"?c:"#000000",typeof d=="string"?d:"#000000",a);if(!y&&(typeof c=="string"||typeof d=="string")){let M=typeof c=="string"&&(c.startsWith("#")||/^[0-9a-f]{6}$/i.test(c)),C=typeof d=="string"&&(d.startsWith("#")||/^[0-9a-f]{6}$/i.test(d));if(M&&C){let E=c.startsWith("#")?c:`#${c}`,S=d.startsWith("#")?d:`#${d}`;return mt(E,S,a)}return d??null}return c+(d-c)*a}return null}var st=.7,Bt=.7;function tt(t,e,n,r,i=null,{rawMode:o=!1}={}){if(!t||!t.parameterStates)return null;let s=o?1:e*r/(st*Bt),l=t.duration||2,m=t.format==="normalized"?n:n*l,c=!0,d=t.parameterStates||{},a=(g,x,T=!0,Y=null)=>{let dt=Y??s,J=Z(d[g]?.points,m,l,c);return J==null?x:T?dt===0?x:x+(J-x)*dt:J},y=a("scale",1),M=a("skew",0),C=a("stretch",1),E=a("translateX",0),S=a("translateY",0),W=a("weight",500),L=a("width",100),P=(t.fontData||{}).style?.fontFamily||"Roboto Flex",V=t.text||"Hello",k=(g,x)=>{let T=Z(d[g]?.points,m,l,c,g);if(T==null)return x;let Y=typeof T=="string"?T.startsWith("#")?T:`#${T}`:`#${Math.round(T).toString(16).padStart(6,"0")}`;return s===0?x:zt(x,Y,s)},X=k("color","#ffffff"),A=a("opacity",1),H=a("shadowX",0),u=a("shadowY",0),p=a("shadowBlur",4),h=a("shadowOpacity",.5),v=k("shadowColor","#000000"),I=a("outlineWidth",0),R=k("outlineColor","#000000"),b=g=>d[g]?.points?.length>0,O=b("stretchX")?a("stretchX",1):void 0,D=b("outline2Width")?a("outline2Width",0):void 0,N=b("outline2Color")?k("outline2Color","#000000"):void 0,_=b("outline3Width")?a("outline3Width",0):void 0,U=b("outline3Color")?k("outline3Color","#000000"):void 0,q=b("outlineShadowWidth")?a("outlineShadowWidth",0):void 0,F=b("outlineShadowColor")?k("outlineShadowColor","#000000"):void 0,z=b("outlineShadowBlur")?a("outlineShadowBlur",0):void 0,$=b("glowIntensity")?a("glowIntensity",0):void 0,G=b("glowColor")?k("glowColor","#ffffff"):void 0,ut=b("snakeWave")?a("snakeWave",0):void 0,ct=b("karaoke")?a("karaoke",0):void 0,Ct=1-.5*Math.min(1,Math.max(0,r)),kt=a("blur",0,!0,o?1:s*Ct),nt=Z(d.thinStroke?.points,m,l,c),rt=Z(d.ascenderHeight?.points,m,l,c),B={};nt!=null&&typeof nt=="number"&&(B.YOPQ=nt),rt!=null&&typeof rt=="number"&&(B.YTAS=rt),W!=null&&(B.wght=W),L!=null&&(B.wdth=L);let j=[];if((H!==0||u!==0||p!==4||h!==.5)&&h>0){let g=typeof v=="string"?v:"#000000",x=parseInt(g.slice(1,3),16),T=parseInt(g.slice(3,5),16),Y=parseInt(g.slice(5,7),16);j.push(`${H}px ${u}px ${p}px rgba(${x}, ${T}, ${Y}, ${h})`)}if($!=null&&$>0){let g=typeof G=="string"?G:"#ffffff";j.push(`0 0 ${$}px ${g}`),j.push(`0 0 ${$*2}px ${g}`),j.push(`0 0 ${$*4}px ${g}`)}let Et=j.length>0?j.join(", "):"",ot=0;if(d.joy?.points&&d.joy.points.length>0)for(let g of d.joy.points){let x=Array.isArray(g)?g[1]:g.y??g.value??0;typeof x=="number"&&x>ot&&(ot=x)}let At=a("joy",0,!1),Mt=o?At:Math.min(1,ot*s),Wt=a("fear",0),Lt=a("standardEmphasis",0,!1),Ft=a("strongEmphasis",0,!1),w={rawIntensity:e,scaleFactor:s,scale:y,slant:M,stretchY:C,translateX:E,translateY:S,weight:W,width:L,fontFamily:P,textColor:X,opacity:A,textShadow:Et,shadowX:H,shadowY:u,blur:kt,outlineWidth:I,outlineColor:R,letterSpacing:`${Math.max(0,(y-1)*.02)}em`,fontVariationAxes:B,text:V,joy:Mt,fear:Wt,standardEmphasis:Lt,strongEmphasis:Ft,joyWaveProgress:m/l*1.5};return O!==void 0&&(w.stretchX=O),D!==void 0&&(w.outline2Width=D),N!==void 0&&(w.outline2Color=N),_!==void 0&&(w.outline3Width=_),U!==void 0&&(w.outline3Color=U),q!==void 0&&(w.outlineShadowWidth=q),F!==void 0&&(w.outlineShadowColor=F),z!==void 0&&(w.outlineShadowBlur=z),$!==void 0&&(w.glowIntensity=$),G!==void 0&&(w.glowColor=G),ut!==void 0&&(w.snakeWave=ut),ct!==void 0&&(w.karaoke=ct),w}var pt={},Vt={"Roboto Flex":"family=Roboto+Flex:opsz,wdth,wght,YOPQ,YTAS@8..144,25..151,100..1000,25..125,649..854&display=swap",Rakkas:"family=Rakkas&display=swap",Parkinsans:"family=Parkinsans:wght@300..800&display=swap","Bricolage Grotesque":"family=Bricolage+Grotesque:opsz,wdth,wght@12..96,75..100,200..800&display=swap",Cormorant:"family=Cormorant:wght@300..700&display=block"};function ht(t){if(!t)return;let e=t.replace(/["']/g,"").split(",")[0].trim();if(!e||e==="sans-serif"||e==="serif"||pt[e]||(pt[e]=!0,typeof document>"u"))return;let n=Vt[e],r=document.createElement("link");r.rel="stylesheet",r.href=n?`https://fonts.googleapis.com/css2?${n}`:`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e)}:wght@100..900&display=swap`,document.head.appendChild(r)}function at(t,e,n){let r=t.split(/\s+/).filter(Boolean);if(r.length===0)return[];let i=n-e,o=r.map(f=>f.length+1),s=o.reduce((f,m)=>f+m,0),l=e;return r.map((f,m)=>{let c=o[m]/s*i,d=Math.round(l*1e3)/1e3;return l+=c,{word:f,start:d,end:Math.round(l*1e3)/1e3}})}function gt(t){let e=t.parentElement;if(e&&e.classList.contains("phont-container"))return e;let n=document.createElement("div");return n.className="phont-container",n.style.cssText="position:relative;display:inline-block;width:100%;line-height:0;background:#000;",t.parentNode.insertBefore(n,t),n.appendChild(t),n}function yt(t){let e=document.createElement("div");return e.className="phont-subtitle-overlay",e.style.cssText="position:absolute;left:0;right:0;bottom:8%;display:flex;justify-content:center;align-items:center;pointer-events:none;z-index:10;padding:0 5%;box-sizing:border-box;",t.appendChild(e),e}function bt(t){let e=document.createElement("span");return e.className="phont-subtitle-text",e.style.cssText="display:inline-flex;flex-wrap:wrap;justify-content:center;align-items:baseline;gap:0;text-align:center;word-spacing:normal;",t.appendChild(e),e}function xt(){let t=document.createElement("style");return t.textContent=".phont-container video::-webkit-media-controls-fullscreen-button{display:none!important}.phont-container:fullscreen{background:#000}.phont-container:fullscreen video{width:100%;height:100%;object-fit:contain}",document.head.appendChild(t),t}function wt(t){let e=document.createElement("button");return e.className="phont-fs-btn",e.setAttribute("aria-label","Fullscreen"),e.innerHTML="&#x26F6;",e.style.cssText="position:absolute;top:12px;right:12px;z-index:20;background:rgba(0,0,0,0.55);border:none;color:#fff;font-size:18px;width:34px;height:34px;border-radius:6px;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s;pointer-events:auto;",t.appendChild(e),e}function lt(t,e){t.innerHTML="";let n=[];for(let r=0;r<e.length;r++){let i=document.createElement("span");i.className="phont-word",i.textContent=e[r].word,i.style.cssText="display:inline-block;white-space:pre;will-change:transform,opacity,margin;transform-origin:center bottom;transition:transform 60ms ease-out,opacity 60ms ease-out,filter 60ms ease-out,color 60ms ease-out,margin 60ms ease-out;",t.appendChild(i),n.push(i),r<e.length-1&&t.appendChild(document.createTextNode(" "))}return n}function Xt(t,e,n,r){t.style.fontSize=r,t.style.fontFamily=e.fontFamily,t.style.fontWeight=String(e.weight),t.style.fontStretch=`${e.width}%`,t.style.fontVariationSettings=`"wght" ${e.weight}, "wdth" ${e.width}`,t.style.color=e.textColor,t.style.transform=`skewX(${e.slant}deg) scaleX(${e.stretchX??1}) scaleY(${e.stretchY}) scale(${e.scale}) translate(${e.translateX}px,${e.translateY}px) translateZ(0)`,t.style.textShadow=e.textShadow||"none",t.style.filter=e.blur>0?`blur(${e.blur}px)`:"none",t.style.letterSpacing=e.letterSpacing,e.outlineWidth>0?(t.style.webkitTextStroke=`${e.outlineWidth}px ${e.outlineColor}`,t.style.paintOrder="stroke fill"):(t.style.webkitTextStroke="",t.style.paintOrder=""),t.style.opacity=String(n?e.opacity:Math.min(.25,e.opacity));let i=e.scale>1.01?(e.scale-1)*(t.textContent?.length||1)*.25:0,o=e.outlineWidth>0?e.outlineWidth*.02:0;t.style.marginLeft=i>0?`${i}em`:"",t.style.marginRight=`${.3+i+o}em`}function St(t,e,n){t.style.fontSize=n,t.style.opacity=e?"1":"0.25",t.style.color="#ffffff",t.style.transform="none",t.style.textShadow="1px 1px 3px rgba(0,0,0,0.7)",t.style.fontWeight="500",t.style.fontStretch="100%",t.style.fontVariationSettings='"wght" 500, "wdth" 100',t.style.filter="none",t.style.webkitTextStroke="",t.style.paintOrder="",t.style.letterSpacing="0em",t.style.marginLeft="",t.style.marginRight="0.3em"}function vt(t,e){let n=e||{},r=typeof t=="string"?document.querySelector(t):t;if(!r)return console.error("[PhontSubtitles] Video element not found:",t),null;let i=r,o=gt(i),s=xt(),l=wt(o),f=yt(o),m=bt(f);o.addEventListener("mouseenter",()=>{l.style.opacity="1"}),o.addEventListener("mouseleave",()=>{l.style.opacity="0"}),l.addEventListener("click",()=>{document.fullscreenElement||document.webkitFullscreenElement?(document.exitFullscreen||document.webkitExitFullscreen).call(document):(o.requestFullscreen||o.webkitRequestFullscreen).call(o)});function c(){let u=document.fullscreenElement||document.webkitFullscreenElement;l.innerHTML=u===o?"&#x2716;":"&#x26F6;"}document.addEventListener("fullscreenchange",c),document.addEventListener("webkitfullscreenchange",c);let d=null,a=null,y=null,M=.7,C=[],E=null,S=null,W=null;function L(){d=null,a=null,y=null,m.innerHTML="",m.style.opacity="0",C=[]}function et(){if(!d||!y||y.length===0){L();return}m.style.opacity="1";let u=i.currentTime,p=n.fontSize||"clamp(1.2rem, 3vw, 2.4rem)";for(let h=0;h<y.length;h++){let v=y[h],I=C[h];if(!I)continue;let R=v.start,b=v.end,O=Math.max(.01,b-R),D=Math.max(0,Math.min(1,(u-R)/O)),N=u>=R,_=u>=R&&u<b,U=u>=b;if(!a){St(I,N,p);continue}let q=v.gts!==void 0?v.gts:M,F;_?F=D:U?F=1:F=0;let z=tt(a,st,F,q,null);if(!z){St(I,N,p);continue}Xt(I,z,N,p)}}function P(){let u=this;if(!u.activeCues||u.activeCues.length===0){L();return}let p=u.activeCues[0];try{let h=JSON.parse(p.text);if(d=p,h.words&&h.words.length>0?y=h.words:y=at(h.text||"",p.startTime,p.endTime),M=typeof h.gts=="number"?h.gts:.7,h.animation_url){a=K(h.animation_url);let v=a.fontData;ht(v?.style?.fontFamily??v?.fontName??null)}else a=null;C=lt(m,y)}catch{d=p,a=null,y=at(p.text||"",p.startTime,p.endTime),C=lt(m,y)}et()}function V(u){return u.kind!=="metadata"?!1:(u.mode="hidden",u.addEventListener("cuechange",P),S=u,!0)}function k(){if(!S||!S.activeCues)return;let u=S.activeCues;if(u.length===0){d&&L(),W=null;return}let p=u[0],h=`${p.startTime}_${p.endTime}`;h!==W&&(W=h,P.call(S))}function X(){k(),d&&et(),E=requestAnimationFrame(X)}let A=i.textTracks,H=!1;for(let u=0;u<A.length;u++)if(V(A[u])){H=!0;break}if(!H){let u=p=>{p.track&&p.track.kind==="metadata"&&(V(p.track),A.removeEventListener("addtrack",u))};A.addEventListener("addtrack",u)}return E=requestAnimationFrame(X),{overlay:f,wordsContainer:m,destroy(){E&&cancelAnimationFrame(E),S&&S.removeEventListener("cuechange",P);for(let u=0;u<A.length;u++)A[u].removeEventListener("cuechange",P);document.removeEventListener("fullscreenchange",c),document.removeEventListener("webkitfullscreenchange",c),s.parentNode&&s.remove(),l.remove(),f.remove()}}}function Tt(t,e){let n=document.createElement("track");return n.kind="metadata",n.src=e,n.default=!0,t.appendChild(n),n}var Ot="0.3.0";
package/dist/browser.mjs CHANGED
@@ -1 +1 @@
1
- function Wt(t,e=!1){if(!t)return[];try{return t.split("|").map(n=>{let[r,i]=n.split(","),o=e||typeof i=="string"&&(i.startsWith("#")||i.startsWith("%23")),s;return o?s=i.replace(/%23/g,"#"):s=parseFloat(i),{time:parseFloat(r),value:s}})}catch(n){return console.error("Error decoding points:",n),[]}}function Lt(t){if(!t)return"";if(t.includes("://"))try{let e=new URL(t);return e.search.startsWith("?")?e.search.slice(1):e.search}catch{let e=t.indexOf("?");return e!==-1?t.substring(e+1):t}return t.startsWith("?")?t.slice(1):t}function rt(t){try{let e=Lt(t),n=new URLSearchParams(e),r={parameterStates:{}};if(n.has("name")&&(r.name=n.get("name")||void 0),n.has("user")&&(r.userName=n.get("user")||void 0),n.has("duration")&&(r.duration=parseFloat(n.get("duration")||"0")),n.has("mode")&&(r.animationMode=n.get("mode")||void 0),n.has("text")&&(r.text=n.get("text")||void 0),n.get("format")==="normalized"&&(r.format="normalized"),n.has("font"))try{let o=JSON.parse(n.get("font")||"{}");o&&typeof o=="object"&&(o.style||o.config||o.fontId?r.fontData={style:o.style,config:o.config||null,fontId:o.fontId||null,fontName:o.fontName||null}:r.fontData={style:o,config:null})}catch(o){console.warn("Failed to parse font data:",o)}if(n.has("bg"))try{r.backgroundStyle=JSON.parse(n.get("bg")||"{}")}catch(o){console.warn("Failed to parse background style:",o)}for(let[o,s]of n.entries())if(!["name","user","duration","mode","text","font","bg","v","c","m","p","format"].includes(o)&&(s.includes("|")||s.includes(","))){let l=o==="color"||o==="shadowColor"||o==="outlineColor"||s.includes("%23"),f=Wt(s,l);if(f.length>0){let m=l?"#000000":0;r.parameterStates[o]={points:f,currentValue:f[0]?.value||m}}}return r}catch(e){throw console.error("Error decoding animation URL:",e),new Error("Failed to decode animation URL. The link may be invalid or corrupted.")}}function Z(t){if(typeof t!="string")return{r:0,g:0,b:0};let e=t.replace("#","").padStart(6,"0"),n=/^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:{r:0,g:0,b:0}}function mt(t,e,n){let r=i=>{let o=Math.round(Math.max(0,Math.min(255,i))).toString(16);return o.length===1?"0"+o:o};return"#"+r(t)+r(e)+r(n)}function dt(t,e,n){let r=Z(t),i=Z(e),o=Math.max(0,Math.min(1,n)),s=r.r+(i.r-r.r)*o,l=r.g+(i.g-r.g)*o,f=r.b+(i.b-r.b)*o;return mt(s,l,f)}function $t(t,e,n){if(n===0)return t;let r=Z(t),i=Z(e),o=r.r+(i.r-r.r)*n,s=r.g+(i.g-r.g)*n,l=r.b+(i.b-r.b)*n;return mt(o,s,l)}function K(t,e,n,r=!1,i=null){if(!t||t.length===0)return null;let o=r?e:e*n,s=null,l=null;for(let f=0;f<t.length;f++){let m=t[f],c=m.time!==void 0?m.time:Array.isArray(m)?m[0]:0;if(c!==void 0&&c<=o&&(s=m),c!==void 0&&c>=o&&!l){l=m;break}}if(!s&&t[0])return(t[0].value!==void 0?t[0].value:Array.isArray(t[0])?t[0][1]:null)??null;if(!l&&s)return(s.value!==void 0?s.value:Array.isArray(s)?s[1]:null)??null;if(s&&l){let f=s.time!==void 0?s.time??0:Array.isArray(s)?s[0]:0,m=l.time!==void 0?l.time??0:Array.isArray(l)?l[0]:0,c=s.value!==void 0?s.value:Array.isArray(s)?s[1]:null,d=l.value!==void 0?l.value:Array.isArray(l)?l[1]:null;if(f===m||c===null||d===null)return c??null;let a=(o-f)/(m-f),y=i==="color"||i==="shadowColor"||i==="outlineColor"||i==="outline2Color"||i==="outline3Color"||i==="outlineShadowColor"||i==="glowColor";if(y&&(typeof c=="string"||typeof d=="string"))return dt(typeof c=="string"?c:"#000000",typeof d=="string"?d:"#000000",a);if(!y&&(typeof c=="string"||typeof d=="string")){let W=typeof c=="string"&&(c.startsWith("#")||/^[0-9a-f]{6}$/i.test(c)),C=typeof d=="string"&&(d.startsWith("#")||/^[0-9a-f]{6}$/i.test(d));if(W&&C){let E=c.startsWith("#")?c:`#${c}`,T=d.startsWith("#")?d:`#${d}`;return dt(E,T,a)}return d??null}return c+(d-c)*a}return null}var ot=.7,Ft=.7;function it(t,e,n,r,i=null,{rawMode:o=!1}={}){if(!t||!t.parameterStates)return null;let s=o?1:e*r/(ot*Ft),l=t.duration||2,m=t.format==="normalized"?n:n*l,c=!0,d=t.parameterStates||{},a=(p,w,v=!0,M=null)=>{let ct=M??s,J=K(d[p]?.points,m,l,c);return J==null?w:v?ct===0?w:w+(J-w)*ct:J},y=a("scale",1),W=a("skew",0),C=a("stretch",1),E=a("translateX",0),T=a("translateY",0),L=a("weight",500),$=a("width",100),I=(t.fontData||{}).style?.fontFamily||"Roboto Flex",V=t.text||"Hello",k=(p,w)=>{let v=K(d[p]?.points,m,l,c,p);if(v==null)return w;let M=typeof v=="string"?v.startsWith("#")?v:`#${v}`:`#${Math.round(v).toString(16).padStart(6,"0")}`;return s===0?w:$t(w,M,s)},O=k("color","#ffffff"),A=a("opacity",1),z=a("shadowX",0),u=a("shadowY",0),h=a("shadowBlur",4),g=a("shadowOpacity",.5),b=k("shadowColor","#000000"),R=a("outlineWidth",0),N=k("outlineColor","#000000"),x=p=>d[p]?.points?.length>0,X=x("stretchX")?a("stretchX",1):void 0,D=x("outline2Width")?a("outline2Width",0):void 0,j=x("outline2Color")?k("outline2Color","#000000"):void 0,_=x("outline3Width")?a("outline3Width",0):void 0,U=x("outline3Color")?k("outline3Color","#000000"):void 0,q=x("outlineShadowWidth")?a("outlineShadowWidth",0):void 0,F=x("outlineShadowColor")?k("outlineShadowColor","#000000"):void 0,Y=x("outlineShadowBlur")?a("outlineShadowBlur",0):void 0,P=x("glowIntensity")?a("glowIntensity",0):void 0,G=x("glowColor")?k("glowColor","#ffffff"):void 0,lt=x("snakeWave")?a("snakeWave",0):void 0,ut=x("karaoke")?a("karaoke",0):void 0,St=1-.5*Math.min(1,Math.max(0,r)),vt=a("blur",0,!0,o?1:s*St),tt=K(d.thinStroke?.points,m,l,c),et=K(d.ascenderHeight?.points,m,l,c),B={};tt!=null&&typeof tt=="number"&&(B.YOPQ=tt),et!=null&&typeof et=="number"&&(B.YTAS=et),L!=null&&(B.wght=L),$!=null&&(B.wdth=$);let H=[];if(z!==0||u!==0||h!==4||g!==.5){let p=typeof b=="string"?b:"#000000",w=parseInt(p.slice(1,3),16),v=parseInt(p.slice(3,5),16),M=parseInt(p.slice(5,7),16);H.push(`${z}px ${u}px ${h}px rgba(${w}, ${v}, ${M}, ${g})`)}else if(b&&typeof b=="string"&&b!=="#000000"){let p=b.startsWith("#")?b:`#${b}`,w=parseInt(p.slice(1,3),16)||0,v=parseInt(p.slice(3,5),16)||0,M=parseInt(p.slice(5,7),16)||0;H.push(`3px 2px 4px rgba(${w}, ${v}, ${M}, 0.5)`)}if(P!=null&&P>0){let p=typeof G=="string"?G:"#ffffff";H.push(`0 0 ${P}px ${p}`),H.push(`0 0 ${P*2}px ${p}`),H.push(`0 0 ${P*4}px ${p}`)}let Tt=H.length>0?H.join(", "):"",nt=0;if(d.joy?.points&&d.joy.points.length>0)for(let p of d.joy.points){let w=Array.isArray(p)?p[1]:p.y??p.value??0;typeof w=="number"&&w>nt&&(nt=w)}let Ct=a("joy",0,!1),kt=o?Ct:Math.min(1,nt*s),Et=a("fear",0),At=a("standardEmphasis",0,!1),Mt=a("strongEmphasis",0,!1),S={rawIntensity:e,scaleFactor:s,scale:y,slant:W,stretchY:C,translateX:E,translateY:T,weight:L,width:$,fontFamily:I,textColor:O,opacity:A,textShadow:Tt,blur:vt,outlineWidth:R,outlineColor:N,letterSpacing:`${Math.max(0,(y-1)*.02)}em`,fontVariationAxes:B,text:V,joy:kt,fear:Et,standardEmphasis:At,strongEmphasis:Mt,joyWaveProgress:m/l*1.5};return X!==void 0&&(S.stretchX=X),D!==void 0&&(S.outline2Width=D),j!==void 0&&(S.outline2Color=j),_!==void 0&&(S.outline3Width=_),U!==void 0&&(S.outline3Color=U),q!==void 0&&(S.outlineShadowWidth=q),F!==void 0&&(S.outlineShadowColor=F),Y!==void 0&&(S.outlineShadowBlur=Y),P!==void 0&&(S.glowIntensity=P),G!==void 0&&(S.glowColor=G),lt!==void 0&&(S.snakeWave=lt),ut!==void 0&&(S.karaoke=ut),S}var ft={},Pt={"Roboto Flex":"family=Roboto+Flex:opsz,wdth,wght,YOPQ,YTAS@8..144,25..151,100..1000,25..125,649..854&display=swap",Rakkas:"family=Rakkas&display=swap",Parkinsans:"family=Parkinsans:wght@300..800&display=swap","Bricolage Grotesque":"family=Bricolage+Grotesque:opsz,wdth,wght@12..96,75..100,200..800&display=swap",Cormorant:"family=Cormorant:wght@300..700&display=block"};function pt(t){if(!t)return;let e=t.replace(/["']/g,"").split(",")[0].trim();if(!e||e==="sans-serif"||e==="serif"||ft[e]||(ft[e]=!0,typeof document>"u"))return;let n=Pt[e],r=document.createElement("link");r.rel="stylesheet",r.href=n?`https://fonts.googleapis.com/css2?${n}`:`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e)}:wght@100..900&display=swap`,document.head.appendChild(r)}function st(t,e,n){let r=t.split(/\s+/).filter(Boolean);if(r.length===0)return[];let i=n-e,o=r.map(f=>f.length+1),s=o.reduce((f,m)=>f+m,0),l=e;return r.map((f,m)=>{let c=o[m]/s*i,d=Math.round(l*1e3)/1e3;return l+=c,{word:f,start:d,end:Math.round(l*1e3)/1e3}})}function ht(t){let e=t.parentElement;if(e&&e.classList.contains("phont-container"))return e;let n=document.createElement("div");return n.className="phont-container",n.style.cssText="position:relative;display:inline-block;width:100%;line-height:0;background:#000;",t.parentNode.insertBefore(n,t),n.appendChild(t),n}function gt(t){let e=document.createElement("div");return e.className="phont-subtitle-overlay",e.style.cssText="position:absolute;left:0;right:0;bottom:8%;display:flex;justify-content:center;align-items:center;pointer-events:none;z-index:10;padding:0 5%;box-sizing:border-box;",t.appendChild(e),e}function yt(t){let e=document.createElement("span");return e.className="phont-subtitle-text",e.style.cssText="display:inline-flex;flex-wrap:wrap;justify-content:center;align-items:baseline;gap:0;text-align:center;word-spacing:normal;",t.appendChild(e),e}function bt(){let t=document.createElement("style");return t.textContent=".phont-container video::-webkit-media-controls-fullscreen-button{display:none!important}.phont-container:fullscreen{background:#000}.phont-container:fullscreen video{width:100%;height:100%;object-fit:contain}",document.head.appendChild(t),t}function xt(t){let e=document.createElement("button");return e.className="phont-fs-btn",e.setAttribute("aria-label","Fullscreen"),e.innerHTML="&#x26F6;",e.style.cssText="position:absolute;top:12px;right:12px;z-index:20;background:rgba(0,0,0,0.55);border:none;color:#fff;font-size:18px;width:34px;height:34px;border-radius:6px;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s;pointer-events:auto;",t.appendChild(e),e}function at(t,e){t.innerHTML="";let n=[];for(let r=0;r<e.length;r++){let i=document.createElement("span");i.className="phont-word",i.textContent=e[r].word,i.style.cssText="display:inline-block;white-space:pre;will-change:transform,opacity,margin;transform-origin:center bottom;transition:transform 60ms ease-out,opacity 60ms ease-out,filter 60ms ease-out,color 60ms ease-out,margin 60ms ease-out;",t.appendChild(i),n.push(i),r<e.length-1&&t.appendChild(document.createTextNode(" "))}return n}function Ht(t,e,n,r){t.style.fontSize=r,t.style.fontFamily=e.fontFamily,t.style.fontWeight=String(e.weight),t.style.fontStretch=`${e.width}%`,t.style.fontVariationSettings=`"wght" ${e.weight}, "wdth" ${e.width}`,t.style.color=e.textColor,t.style.transform=`skewX(${e.slant}deg) scaleX(${e.stretchX??1}) scaleY(${e.stretchY}) scale(${e.scale}) translate(${e.translateX}px,${e.translateY}px) translateZ(0)`,t.style.textShadow=e.textShadow||"none",t.style.filter=e.blur>0?`blur(${e.blur}px)`:"none",t.style.letterSpacing=e.letterSpacing,e.outlineWidth>0?(t.style.webkitTextStroke=`${e.outlineWidth}px ${e.outlineColor}`,t.style.paintOrder="stroke fill"):(t.style.webkitTextStroke="",t.style.paintOrder=""),t.style.opacity=String(n?e.opacity:Math.min(.25,e.opacity));let i=e.scale>1.01?(e.scale-1)*(t.textContent?.length||1)*.25:0,o=e.outlineWidth>0?e.outlineWidth*.02:0;t.style.marginLeft=i>0?`${i}em`:"",t.style.marginRight=`${.3+i+o}em`}function wt(t,e,n){t.style.fontSize=n,t.style.opacity=e?"1":"0.25",t.style.color="#ffffff",t.style.transform="none",t.style.textShadow="1px 1px 3px rgba(0,0,0,0.7)",t.style.fontWeight="500",t.style.fontStretch="100%",t.style.fontVariationSettings='"wght" 500, "wdth" 100',t.style.filter="none",t.style.webkitTextStroke="",t.style.paintOrder="",t.style.letterSpacing="0em",t.style.marginLeft="",t.style.marginRight="0.3em"}function It(t,e){let n=e||{},r=typeof t=="string"?document.querySelector(t):t;if(!r)return console.error("[PhontSubtitles] Video element not found:",t),null;let i=r,o=ht(i),s=bt(),l=xt(o),f=gt(o),m=yt(f);o.addEventListener("mouseenter",()=>{l.style.opacity="1"}),o.addEventListener("mouseleave",()=>{l.style.opacity="0"}),l.addEventListener("click",()=>{document.fullscreenElement||document.webkitFullscreenElement?(document.exitFullscreen||document.webkitExitFullscreen).call(document):(o.requestFullscreen||o.webkitRequestFullscreen).call(o)});function c(){let u=document.fullscreenElement||document.webkitFullscreenElement;l.innerHTML=u===o?"&#x2716;":"&#x26F6;"}document.addEventListener("fullscreenchange",c),document.addEventListener("webkitfullscreenchange",c);let d=null,a=null,y=null,W=.7,C=[],E=null,T=null,L=null;function $(){d=null,a=null,y=null,m.innerHTML="",m.style.opacity="0",C=[]}function Q(){if(!d||!y||y.length===0){$();return}m.style.opacity="1";let u=i.currentTime,h=n.fontSize||"clamp(1.2rem, 3vw, 2.4rem)";for(let g=0;g<y.length;g++){let b=y[g],R=C[g];if(!R)continue;let N=b.start,x=b.end,X=Math.max(.01,x-N),D=Math.max(0,Math.min(1,(u-N)/X)),j=u>=N,_=u>=N&&u<x,U=u>=x;if(!a){wt(R,j,h);continue}let q=b.gts!==void 0?b.gts:W,F;_?F=D:U?F=1:F=0;let Y=it(a,ot,F,q,null);if(!Y){wt(R,j,h);continue}Ht(R,Y,j,h)}}function I(){let u=this;if(!u.activeCues||u.activeCues.length===0){$();return}let h=u.activeCues[0];try{let g=JSON.parse(h.text);if(d=h,g.words&&g.words.length>0?y=g.words:y=st(g.text||"",h.startTime,h.endTime),W=typeof g.gts=="number"?g.gts:.7,g.animation_url){a=rt(g.animation_url);let b=a.fontData;pt(b?.style?.fontFamily??b?.fontName??null)}else a=null;C=at(m,y)}catch{d=h,a=null,y=st(h.text||"",h.startTime,h.endTime),C=at(m,y)}Q()}function V(u){return u.kind!=="metadata"?!1:(u.mode="hidden",u.addEventListener("cuechange",I),T=u,!0)}function k(){if(!T||!T.activeCues)return;let u=T.activeCues;if(u.length===0){d&&$(),L=null;return}let h=u[0],g=`${h.startTime}_${h.endTime}`;g!==L&&(L=g,I.call(T))}function O(){k(),d&&Q(),E=requestAnimationFrame(O)}let A=i.textTracks,z=!1;for(let u=0;u<A.length;u++)if(V(A[u])){z=!0;break}if(!z){let u=h=>{h.track&&h.track.kind==="metadata"&&(V(h.track),A.removeEventListener("addtrack",u))};A.addEventListener("addtrack",u)}return E=requestAnimationFrame(O),{overlay:f,wordsContainer:m,destroy(){E&&cancelAnimationFrame(E),T&&T.removeEventListener("cuechange",I);for(let u=0;u<A.length;u++)A[u].removeEventListener("cuechange",I);document.removeEventListener("fullscreenchange",c),document.removeEventListener("webkitfullscreenchange",c),s.parentNode&&s.remove(),l.remove(),f.remove()}}}function Rt(t,e){let n=document.createElement("track");return n.kind="metadata",n.src=e,n.default=!0,t.appendChild(n),n}var Gt="0.3.0";export{It as attach,rt as decodeAnimationUrl,Rt as loadMetadataTrack,it as sampleAt,Gt as version};
1
+ function Wt(t,e=!1){if(!t)return[];try{return t.split("|").map(n=>{let[r,i]=n.split(","),o=e||typeof i=="string"&&(i.startsWith("#")||i.startsWith("%23")),s;return o?s=i.replace(/%23/g,"#"):s=parseFloat(i),{time:parseFloat(r),value:s}})}catch(n){return console.error("Error decoding points:",n),[]}}function Lt(t){if(!t)return"";if(t.includes("://"))try{let e=new URL(t);return e.search.startsWith("?")?e.search.slice(1):e.search}catch{let e=t.indexOf("?");return e!==-1?t.substring(e+1):t}return t.startsWith("?")?t.slice(1):t}function rt(t){try{let e=Lt(t),n=new URLSearchParams(e),r={parameterStates:{}};if(n.has("name")&&(r.name=n.get("name")||void 0),n.has("user")&&(r.userName=n.get("user")||void 0),n.has("duration")&&(r.duration=parseFloat(n.get("duration")||"0")),n.has("mode")&&(r.animationMode=n.get("mode")||void 0),n.has("text")&&(r.text=n.get("text")||void 0),n.get("format")==="normalized"&&(r.format="normalized"),n.has("font"))try{let o=JSON.parse(n.get("font")||"{}");o&&typeof o=="object"&&(o.style||o.config||o.fontId?r.fontData={style:o.style,config:o.config||null,fontId:o.fontId||null,fontName:o.fontName||null}:r.fontData={style:o,config:null})}catch(o){console.warn("Failed to parse font data:",o)}if(n.has("bg"))try{r.backgroundStyle=JSON.parse(n.get("bg")||"{}")}catch(o){console.warn("Failed to parse background style:",o)}for(let[o,s]of n.entries())if(!["name","user","duration","mode","text","font","bg","v","c","m","p","format"].includes(o)&&(s.includes("|")||s.includes(","))){let l=o==="color"||o==="shadowColor"||o==="outlineColor"||s.includes("%23"),f=Wt(s,l);if(f.length>0){let m=l?"#000000":0;r.parameterStates[o]={points:f,currentValue:f[0]?.value||m}}}return r}catch(e){throw console.error("Error decoding animation URL:",e),new Error("Failed to decode animation URL. The link may be invalid or corrupted.")}}function Z(t){if(typeof t!="string")return{r:0,g:0,b:0};let e=t.replace("#","").padStart(6,"0"),n=/^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return n?{r:parseInt(n[1],16),g:parseInt(n[2],16),b:parseInt(n[3],16)}:{r:0,g:0,b:0}}function mt(t,e,n){let r=i=>{let o=Math.round(Math.max(0,Math.min(255,i))).toString(16);return o.length===1?"0"+o:o};return"#"+r(t)+r(e)+r(n)}function dt(t,e,n){let r=Z(t),i=Z(e),o=Math.max(0,Math.min(1,n)),s=r.r+(i.r-r.r)*o,l=r.g+(i.g-r.g)*o,f=r.b+(i.b-r.b)*o;return mt(s,l,f)}function Ft(t,e,n){if(n===0)return t;let r=Z(t),i=Z(e),o=r.r+(i.r-r.r)*n,s=r.g+(i.g-r.g)*n,l=r.b+(i.b-r.b)*n;return mt(o,s,l)}function K(t,e,n,r=!1,i=null){if(!t||t.length===0)return null;let o=r?e:e*n,s=null,l=null;for(let f=0;f<t.length;f++){let m=t[f],c=m.time!==void 0?m.time:Array.isArray(m)?m[0]:0;if(c!==void 0&&c<=o&&(s=m),c!==void 0&&c>=o&&!l){l=m;break}}if(!s&&t[0])return(t[0].value!==void 0?t[0].value:Array.isArray(t[0])?t[0][1]:null)??null;if(!l&&s)return(s.value!==void 0?s.value:Array.isArray(s)?s[1]:null)??null;if(s&&l){let f=s.time!==void 0?s.time??0:Array.isArray(s)?s[0]:0,m=l.time!==void 0?l.time??0:Array.isArray(l)?l[0]:0,c=s.value!==void 0?s.value:Array.isArray(s)?s[1]:null,d=l.value!==void 0?l.value:Array.isArray(l)?l[1]:null;if(f===m||c===null||d===null)return c??null;let a=(o-f)/(m-f),y=i==="color"||i==="shadowColor"||i==="outlineColor"||i==="outline2Color"||i==="outline3Color"||i==="outlineShadowColor"||i==="glowColor";if(y&&(typeof c=="string"||typeof d=="string"))return dt(typeof c=="string"?c:"#000000",typeof d=="string"?d:"#000000",a);if(!y&&(typeof c=="string"||typeof d=="string")){let M=typeof c=="string"&&(c.startsWith("#")||/^[0-9a-f]{6}$/i.test(c)),C=typeof d=="string"&&(d.startsWith("#")||/^[0-9a-f]{6}$/i.test(d));if(M&&C){let E=c.startsWith("#")?c:`#${c}`,S=d.startsWith("#")?d:`#${d}`;return dt(E,S,a)}return d??null}return c+(d-c)*a}return null}var ot=.7,$t=.7;function it(t,e,n,r,i=null,{rawMode:o=!1}={}){if(!t||!t.parameterStates)return null;let s=o?1:e*r/(ot*$t),l=t.duration||2,m=t.format==="normalized"?n:n*l,c=!0,d=t.parameterStates||{},a=(g,x,T=!0,Y=null)=>{let ct=Y??s,J=K(d[g]?.points,m,l,c);return J==null?x:T?ct===0?x:x+(J-x)*ct:J},y=a("scale",1),M=a("skew",0),C=a("stretch",1),E=a("translateX",0),S=a("translateY",0),W=a("weight",500),L=a("width",100),P=(t.fontData||{}).style?.fontFamily||"Roboto Flex",V=t.text||"Hello",k=(g,x)=>{let T=K(d[g]?.points,m,l,c,g);if(T==null)return x;let Y=typeof T=="string"?T.startsWith("#")?T:`#${T}`:`#${Math.round(T).toString(16).padStart(6,"0")}`;return s===0?x:Ft(x,Y,s)},X=k("color","#ffffff"),A=a("opacity",1),H=a("shadowX",0),u=a("shadowY",0),p=a("shadowBlur",4),h=a("shadowOpacity",.5),v=k("shadowColor","#000000"),I=a("outlineWidth",0),R=k("outlineColor","#000000"),b=g=>d[g]?.points?.length>0,O=b("stretchX")?a("stretchX",1):void 0,D=b("outline2Width")?a("outline2Width",0):void 0,N=b("outline2Color")?k("outline2Color","#000000"):void 0,_=b("outline3Width")?a("outline3Width",0):void 0,U=b("outline3Color")?k("outline3Color","#000000"):void 0,q=b("outlineShadowWidth")?a("outlineShadowWidth",0):void 0,F=b("outlineShadowColor")?k("outlineShadowColor","#000000"):void 0,z=b("outlineShadowBlur")?a("outlineShadowBlur",0):void 0,$=b("glowIntensity")?a("glowIntensity",0):void 0,G=b("glowColor")?k("glowColor","#ffffff"):void 0,lt=b("snakeWave")?a("snakeWave",0):void 0,ut=b("karaoke")?a("karaoke",0):void 0,St=1-.5*Math.min(1,Math.max(0,r)),vt=a("blur",0,!0,o?1:s*St),tt=K(d.thinStroke?.points,m,l,c),et=K(d.ascenderHeight?.points,m,l,c),B={};tt!=null&&typeof tt=="number"&&(B.YOPQ=tt),et!=null&&typeof et=="number"&&(B.YTAS=et),W!=null&&(B.wght=W),L!=null&&(B.wdth=L);let j=[];if((H!==0||u!==0||p!==4||h!==.5)&&h>0){let g=typeof v=="string"?v:"#000000",x=parseInt(g.slice(1,3),16),T=parseInt(g.slice(3,5),16),Y=parseInt(g.slice(5,7),16);j.push(`${H}px ${u}px ${p}px rgba(${x}, ${T}, ${Y}, ${h})`)}if($!=null&&$>0){let g=typeof G=="string"?G:"#ffffff";j.push(`0 0 ${$}px ${g}`),j.push(`0 0 ${$*2}px ${g}`),j.push(`0 0 ${$*4}px ${g}`)}let Tt=j.length>0?j.join(", "):"",nt=0;if(d.joy?.points&&d.joy.points.length>0)for(let g of d.joy.points){let x=Array.isArray(g)?g[1]:g.y??g.value??0;typeof x=="number"&&x>nt&&(nt=x)}let Ct=a("joy",0,!1),kt=o?Ct:Math.min(1,nt*s),Et=a("fear",0),At=a("standardEmphasis",0,!1),Mt=a("strongEmphasis",0,!1),w={rawIntensity:e,scaleFactor:s,scale:y,slant:M,stretchY:C,translateX:E,translateY:S,weight:W,width:L,fontFamily:P,textColor:X,opacity:A,textShadow:Tt,shadowX:H,shadowY:u,blur:vt,outlineWidth:I,outlineColor:R,letterSpacing:`${Math.max(0,(y-1)*.02)}em`,fontVariationAxes:B,text:V,joy:kt,fear:Et,standardEmphasis:At,strongEmphasis:Mt,joyWaveProgress:m/l*1.5};return O!==void 0&&(w.stretchX=O),D!==void 0&&(w.outline2Width=D),N!==void 0&&(w.outline2Color=N),_!==void 0&&(w.outline3Width=_),U!==void 0&&(w.outline3Color=U),q!==void 0&&(w.outlineShadowWidth=q),F!==void 0&&(w.outlineShadowColor=F),z!==void 0&&(w.outlineShadowBlur=z),$!==void 0&&(w.glowIntensity=$),G!==void 0&&(w.glowColor=G),lt!==void 0&&(w.snakeWave=lt),ut!==void 0&&(w.karaoke=ut),w}var ft={},Pt={"Roboto Flex":"family=Roboto+Flex:opsz,wdth,wght,YOPQ,YTAS@8..144,25..151,100..1000,25..125,649..854&display=swap",Rakkas:"family=Rakkas&display=swap",Parkinsans:"family=Parkinsans:wght@300..800&display=swap","Bricolage Grotesque":"family=Bricolage+Grotesque:opsz,wdth,wght@12..96,75..100,200..800&display=swap",Cormorant:"family=Cormorant:wght@300..700&display=block"};function pt(t){if(!t)return;let e=t.replace(/["']/g,"").split(",")[0].trim();if(!e||e==="sans-serif"||e==="serif"||ft[e]||(ft[e]=!0,typeof document>"u"))return;let n=Pt[e],r=document.createElement("link");r.rel="stylesheet",r.href=n?`https://fonts.googleapis.com/css2?${n}`:`https://fonts.googleapis.com/css2?family=${encodeURIComponent(e)}:wght@100..900&display=swap`,document.head.appendChild(r)}function st(t,e,n){let r=t.split(/\s+/).filter(Boolean);if(r.length===0)return[];let i=n-e,o=r.map(f=>f.length+1),s=o.reduce((f,m)=>f+m,0),l=e;return r.map((f,m)=>{let c=o[m]/s*i,d=Math.round(l*1e3)/1e3;return l+=c,{word:f,start:d,end:Math.round(l*1e3)/1e3}})}function ht(t){let e=t.parentElement;if(e&&e.classList.contains("phont-container"))return e;let n=document.createElement("div");return n.className="phont-container",n.style.cssText="position:relative;display:inline-block;width:100%;line-height:0;background:#000;",t.parentNode.insertBefore(n,t),n.appendChild(t),n}function gt(t){let e=document.createElement("div");return e.className="phont-subtitle-overlay",e.style.cssText="position:absolute;left:0;right:0;bottom:8%;display:flex;justify-content:center;align-items:center;pointer-events:none;z-index:10;padding:0 5%;box-sizing:border-box;",t.appendChild(e),e}function yt(t){let e=document.createElement("span");return e.className="phont-subtitle-text",e.style.cssText="display:inline-flex;flex-wrap:wrap;justify-content:center;align-items:baseline;gap:0;text-align:center;word-spacing:normal;",t.appendChild(e),e}function bt(){let t=document.createElement("style");return t.textContent=".phont-container video::-webkit-media-controls-fullscreen-button{display:none!important}.phont-container:fullscreen{background:#000}.phont-container:fullscreen video{width:100%;height:100%;object-fit:contain}",document.head.appendChild(t),t}function xt(t){let e=document.createElement("button");return e.className="phont-fs-btn",e.setAttribute("aria-label","Fullscreen"),e.innerHTML="&#x26F6;",e.style.cssText="position:absolute;top:12px;right:12px;z-index:20;background:rgba(0,0,0,0.55);border:none;color:#fff;font-size:18px;width:34px;height:34px;border-radius:6px;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transition:opacity .2s;pointer-events:auto;",t.appendChild(e),e}function at(t,e){t.innerHTML="";let n=[];for(let r=0;r<e.length;r++){let i=document.createElement("span");i.className="phont-word",i.textContent=e[r].word,i.style.cssText="display:inline-block;white-space:pre;will-change:transform,opacity,margin;transform-origin:center bottom;transition:transform 60ms ease-out,opacity 60ms ease-out,filter 60ms ease-out,color 60ms ease-out,margin 60ms ease-out;",t.appendChild(i),n.push(i),r<e.length-1&&t.appendChild(document.createTextNode(" "))}return n}function Ht(t,e,n,r){t.style.fontSize=r,t.style.fontFamily=e.fontFamily,t.style.fontWeight=String(e.weight),t.style.fontStretch=`${e.width}%`,t.style.fontVariationSettings=`"wght" ${e.weight}, "wdth" ${e.width}`,t.style.color=e.textColor,t.style.transform=`skewX(${e.slant}deg) scaleX(${e.stretchX??1}) scaleY(${e.stretchY}) scale(${e.scale}) translate(${e.translateX}px,${e.translateY}px) translateZ(0)`,t.style.textShadow=e.textShadow||"none",t.style.filter=e.blur>0?`blur(${e.blur}px)`:"none",t.style.letterSpacing=e.letterSpacing,e.outlineWidth>0?(t.style.webkitTextStroke=`${e.outlineWidth}px ${e.outlineColor}`,t.style.paintOrder="stroke fill"):(t.style.webkitTextStroke="",t.style.paintOrder=""),t.style.opacity=String(n?e.opacity:Math.min(.25,e.opacity));let i=e.scale>1.01?(e.scale-1)*(t.textContent?.length||1)*.25:0,o=e.outlineWidth>0?e.outlineWidth*.02:0;t.style.marginLeft=i>0?`${i}em`:"",t.style.marginRight=`${.3+i+o}em`}function wt(t,e,n){t.style.fontSize=n,t.style.opacity=e?"1":"0.25",t.style.color="#ffffff",t.style.transform="none",t.style.textShadow="1px 1px 3px rgba(0,0,0,0.7)",t.style.fontWeight="500",t.style.fontStretch="100%",t.style.fontVariationSettings='"wght" 500, "wdth" 100',t.style.filter="none",t.style.webkitTextStroke="",t.style.paintOrder="",t.style.letterSpacing="0em",t.style.marginLeft="",t.style.marginRight="0.3em"}function It(t,e){let n=e||{},r=typeof t=="string"?document.querySelector(t):t;if(!r)return console.error("[PhontSubtitles] Video element not found:",t),null;let i=r,o=ht(i),s=bt(),l=xt(o),f=gt(o),m=yt(f);o.addEventListener("mouseenter",()=>{l.style.opacity="1"}),o.addEventListener("mouseleave",()=>{l.style.opacity="0"}),l.addEventListener("click",()=>{document.fullscreenElement||document.webkitFullscreenElement?(document.exitFullscreen||document.webkitExitFullscreen).call(document):(o.requestFullscreen||o.webkitRequestFullscreen).call(o)});function c(){let u=document.fullscreenElement||document.webkitFullscreenElement;l.innerHTML=u===o?"&#x2716;":"&#x26F6;"}document.addEventListener("fullscreenchange",c),document.addEventListener("webkitfullscreenchange",c);let d=null,a=null,y=null,M=.7,C=[],E=null,S=null,W=null;function L(){d=null,a=null,y=null,m.innerHTML="",m.style.opacity="0",C=[]}function Q(){if(!d||!y||y.length===0){L();return}m.style.opacity="1";let u=i.currentTime,p=n.fontSize||"clamp(1.2rem, 3vw, 2.4rem)";for(let h=0;h<y.length;h++){let v=y[h],I=C[h];if(!I)continue;let R=v.start,b=v.end,O=Math.max(.01,b-R),D=Math.max(0,Math.min(1,(u-R)/O)),N=u>=R,_=u>=R&&u<b,U=u>=b;if(!a){wt(I,N,p);continue}let q=v.gts!==void 0?v.gts:M,F;_?F=D:U?F=1:F=0;let z=it(a,ot,F,q,null);if(!z){wt(I,N,p);continue}Ht(I,z,N,p)}}function P(){let u=this;if(!u.activeCues||u.activeCues.length===0){L();return}let p=u.activeCues[0];try{let h=JSON.parse(p.text);if(d=p,h.words&&h.words.length>0?y=h.words:y=st(h.text||"",p.startTime,p.endTime),M=typeof h.gts=="number"?h.gts:.7,h.animation_url){a=rt(h.animation_url);let v=a.fontData;pt(v?.style?.fontFamily??v?.fontName??null)}else a=null;C=at(m,y)}catch{d=p,a=null,y=st(p.text||"",p.startTime,p.endTime),C=at(m,y)}Q()}function V(u){return u.kind!=="metadata"?!1:(u.mode="hidden",u.addEventListener("cuechange",P),S=u,!0)}function k(){if(!S||!S.activeCues)return;let u=S.activeCues;if(u.length===0){d&&L(),W=null;return}let p=u[0],h=`${p.startTime}_${p.endTime}`;h!==W&&(W=h,P.call(S))}function X(){k(),d&&Q(),E=requestAnimationFrame(X)}let A=i.textTracks,H=!1;for(let u=0;u<A.length;u++)if(V(A[u])){H=!0;break}if(!H){let u=p=>{p.track&&p.track.kind==="metadata"&&(V(p.track),A.removeEventListener("addtrack",u))};A.addEventListener("addtrack",u)}return E=requestAnimationFrame(X),{overlay:f,wordsContainer:m,destroy(){E&&cancelAnimationFrame(E),S&&S.removeEventListener("cuechange",P);for(let u=0;u<A.length;u++)A[u].removeEventListener("cuechange",P);document.removeEventListener("fullscreenchange",c),document.removeEventListener("webkitfullscreenchange",c),s.parentNode&&s.remove(),l.remove(),f.remove()}}}function Rt(t,e){let n=document.createElement("track");return n.kind="metadata",n.src=e,n.default=!0,t.appendChild(n),n}var Gt="0.3.0";export{It as attach,rt as decodeAnimationUrl,Rt as loadMetadataTrack,it as sampleAt,Gt as version};
package/dist/index.d.mts CHANGED
@@ -381,8 +381,17 @@ declare class SubtitleManager {
381
381
  normalizeSubtitles(data: any): any;
382
382
  normalizeSoundbites(arr: any[]): any[];
383
383
  getAudioSegmentDuration(sequenceNumber: number): Promise<number>;
384
+ /**
385
+ * Configure the live HLS master URL at runtime. Required for SDK consumers
386
+ * who don't set NEXT_PUBLIC_API_LIVE_URL at build time. When set, fetches
387
+ * use sidecar mode against this URL.
388
+ */
389
+ setLiveMasterUrl(url: string | null): void;
384
390
  getInitialLiveSequenceNumber(): Promise<number>;
385
- fetchSubtitles(sequenceNumber: number): Promise<any | null>;
391
+ recordSegmentDuration(sequenceNumber: number, duration: number): void;
392
+ recordInitialSequenceOffset(sequenceNumber: number): void;
393
+ fetchSubtitles(sequenceNumber: number, fragStart: number): Promise<any | null>;
394
+ updateLiveTimeFromVideo(videoTime: number): void;
386
395
  loadVodSubtitles(urlOrVodId: string, languageCode?: string | null): Promise<void>;
387
396
  _processVodData(data: any, url: string, languageCode: string | null, originalSubtitles?: any[]): void;
388
397
  getSubtitleForTime(time: number): any;
@@ -414,6 +423,145 @@ declare class SubtitleManager {
414
423
  }
415
424
  declare const subtitleManager: SubtitleManager;
416
425
 
426
+ /**
427
+ * LiveSegmentSource — player-agnostic interface for the live subtitle
428
+ * pipeline.
429
+ *
430
+ * Each concrete adapter (hls.js / Shaka / Bitmovin) wraps a player
431
+ * instance and normalizes its segment-lifecycle events into the two
432
+ * callbacks below. The subtitle hook subscribes to a `LiveSegmentSource`
433
+ * and never imports a player SDK directly, so swapping players is a
434
+ * one-file change.
435
+ *
436
+ * Contract:
437
+ * - `onInitialPlaylist` MUST fire exactly once, with the fragments
438
+ * visible in the first playlist the player parses. Subscribers use
439
+ * it for backfill.
440
+ * - `onSegmentLoaded` fires once per audio-aligned segment as the
441
+ * player loads it. Adapters MUST dedupe by `sn` so subscribers see
442
+ * each segment at most once across the lifetime of the source.
443
+ * - Sequence numbers (`sn`) are the HLS media-sequence integer. For
444
+ * DASH or other manifest formats, the adapter is responsible for
445
+ * synthesizing an equivalent monotonically-increasing integer.
446
+ */
447
+ interface SegmentInfo {
448
+ /** HLS media sequence number. */
449
+ sn: number;
450
+ /** Segment duration in seconds. */
451
+ duration: number;
452
+ /**
453
+ * Presentation-timeline start of this fragment, in the same space as
454
+ * `video.currentTime`. Used to anchor subtitle cues directly to media
455
+ * time.
456
+ */
457
+ start?: number;
458
+ /** Resolved segment URL (debugging only). */
459
+ uri?: string;
460
+ /** `'main'` | `'audio'` | `'subtitle'`. */
461
+ type?: string;
462
+ }
463
+ interface InitialPlaylist {
464
+ /** Media-sequence of the first fragment. */
465
+ startSn: number;
466
+ /** All fragments in the initial window. */
467
+ fragments: SegmentInfo[];
468
+ /** URI of the playlist these came from. */
469
+ playlistUri?: string;
470
+ }
471
+ type SegmentListener = (info: SegmentInfo) => void;
472
+ type InitialPlaylistListener = (info: InitialPlaylist) => void;
473
+ interface LiveSegmentSource {
474
+ /**
475
+ * Subscribe to per-segment-loaded events. Returns a teardown function
476
+ * that unregisters the listener.
477
+ */
478
+ onSegmentLoaded(cb: SegmentListener): () => void;
479
+ /**
480
+ * Subscribe to the once-per-stream initial-playlist event. Returns a
481
+ * teardown function that unregisters the listener.
482
+ */
483
+ onInitialPlaylist(cb: InitialPlaylistListener): () => void;
484
+ /**
485
+ * Tear down the adapter — unhook all player events, clear listener
486
+ * sets. Safe to call multiple times.
487
+ */
488
+ destroy(): void;
489
+ }
490
+ /**
491
+ * Build a `LiveSegmentSource` with shared listener bookkeeping. Concrete
492
+ * adapters call `emitSegment` / `emitInitial` when their underlying
493
+ * player fires the corresponding event, and register cleanup hooks via
494
+ * `addTeardown`.
495
+ */
496
+ declare function createLiveSegmentSource(): {
497
+ source: LiveSegmentSource;
498
+ emitSegment: (info: SegmentInfo) => void;
499
+ emitInitial: (info: InitialPlaylist) => void;
500
+ addTeardown: (fn: () => void) => void;
501
+ };
502
+
503
+ /**
504
+ * Wrap an hls.js instance into a LiveSegmentSource.
505
+ *
506
+ * Most AMS HLS output is muxed (combined A+V under one playlist,
507
+ * `frag.type === 'main'`) but split-audio renditions also exist
508
+ * (`frag.type === 'audio'`). We accept both and dedupe by `sn`, so
509
+ * whichever fires first per sequence wins.
510
+ *
511
+ * Initial playlist comes from `LEVEL_LOADED` (muxed) or
512
+ * `AUDIO_TRACK_LOADED` (split). First one with fragments wins.
513
+ *
514
+ * @param hls The hls.js instance (from `new Hls()`).
515
+ * @param Hls The hls.js namespace (for `Hls.Events`). hls.js doesn't
516
+ * re-export `Events` off instances; callers pass the
517
+ * imported module's default.
518
+ */
519
+ declare function createHlsLiveSegmentSource(hls: any, Hls: any): LiveSegmentSource;
520
+
521
+ /**
522
+ * Wrap a shaka.Player instance into a LiveSegmentSource.
523
+ *
524
+ * NOT YET IMPLEMENTED — placeholder so the adapter layout is in place.
525
+ *
526
+ * Implementation outline:
527
+ * - Segment-loaded:
528
+ * Use `player.getNetworkingEngine().registerResponseFilter((type, response) => …)`
529
+ * and filter `type === shaka.net.NetworkingEngine.RequestType.SEGMENT`.
530
+ * Shaka does not surface an HLS media-sequence number directly;
531
+ * parse it out of `response.uri` (the AMS segment filenames carry
532
+ * the sn), or compute it as
533
+ * `Math.round(response.timeMs * 1000 / segmentDurationMs)`.
534
+ * - Initial playlist:
535
+ * Listen for the `manifestparsed` event on the player. Walk
536
+ * `player.getVariantTracks()` / the parsed manifest to gather the
537
+ * initial fragments. Shaka's HLS parser keeps the sn in the
538
+ * segment references; you may need to dip into private API or
539
+ * parse the playlist text yourself.
540
+ * - Don't forget to remove the response filter in `destroy`.
541
+ */
542
+ declare function createShakaLiveSegmentSource(_player: any, _shaka: any): LiveSegmentSource;
543
+
544
+ /**
545
+ * Wrap a Bitmovin Player instance into a LiveSegmentSource.
546
+ *
547
+ * NOT YET IMPLEMENTED — placeholder so the adapter layout is in place.
548
+ *
549
+ * Implementation outline:
550
+ * - Segment-loaded:
551
+ * Subscribe to `PlayerEvent.SegmentRequestFinished`. The event
552
+ * payload includes `mediaType` (audio/video) and a `url`. Parse
553
+ * the HLS sn out of the segment URL (AMS encodes it in the
554
+ * filename), or maintain a counter keyed off the playlist start
555
+ * sn.
556
+ * - Initial playlist:
557
+ * Subscribe to `PlayerEvent.SourceLoaded` and read the parsed
558
+ * manifest via the player's manifest API. Walk audio (or muxed)
559
+ * segments to build the initial-window list.
560
+ * - `destroy` MUST `player.off(...)` everything to avoid leaks across
561
+ * hot reloads.
562
+ */
563
+ declare function createBitmovinLiveSegmentSource(_player: any): LiveSegmentSource;
564
+
417
565
  /**
418
566
  * URL Decoder for Animation Parameters
419
567
  *
@@ -484,6 +632,8 @@ interface AnimationParameterState {
484
632
  textColor: string;
485
633
  opacity: number;
486
634
  textShadow: string;
635
+ shadowX?: number;
636
+ shadowY?: number;
487
637
  blur: number;
488
638
  outlineWidth: number;
489
639
  outlineColor: string;
@@ -739,6 +889,15 @@ declare const ANIMATION_STYLING: {
739
889
  minDisplayTime: number;
740
890
  allowOverlap: boolean;
741
891
  };
892
+ subtitleBackground: {
893
+ background: string;
894
+ border: string;
895
+ borderRadius: number;
896
+ boxShadow: string;
897
+ backdropFilter: string;
898
+ paddingX: number;
899
+ paddingY: number;
900
+ };
742
901
  };
743
902
 
744
903
  /**
@@ -889,6 +1048,107 @@ declare function generateTextShadow(shadowColor: string | undefined, _fontFamily
889
1048
  * @returns CSS em value for marginRight
890
1049
  */
891
1050
  declare function calculateDynamicWordSpacing(currentScale?: number, fontFamily?: string, gtsIntensity?: number, emotion?: string): string;
1051
+ /**
1052
+ * Tighter spacing for a single animated word in an otherwise normal line.
1053
+ * Full calculateDynamicWordSpacing assumes the whole line scales together;
1054
+ * per-word pops (e.g. spain-goal on one word) only need room for local overflow.
1055
+ */
1056
+ declare function calculatePerWordSpacing(currentScale?: number, fontFamily?: string, gtsIntensity?: number, emotion?: string): string;
1057
+
1058
+ /**
1059
+ * Resolve which animation URL / emotion / intensity apply to a single word.
1060
+ * Word-level fields override segment defaults when present.
1061
+ */
1062
+ interface WordAnimationFields {
1063
+ animation_url?: string | null;
1064
+ emotion?: string | null;
1065
+ emotion_intensity?: number | null;
1066
+ }
1067
+ interface WordAnimationSource {
1068
+ animationUrl: string | null;
1069
+ emotion: string | null;
1070
+ emotionIntensity: number | null;
1071
+ hasWordOverride: boolean;
1072
+ }
1073
+ declare function hasWordAnimationOverride(word: WordAnimationFields | null | undefined): boolean;
1074
+ declare function resolveWordAnimationSource(word: WordAnimationFields | null | undefined, segment: WordAnimationFields | null | undefined): WordAnimationSource;
1075
+
1076
+ /**
1077
+ * Helpers for author-assigned vs auto-detected subtitle animations.
1078
+ */
1079
+
1080
+ declare const NORMAL_ANIMATION_EMOTIONS: Set<string>;
1081
+ declare function isNormalAnimationEmotion(emotion: string | null | undefined): boolean;
1082
+ /**
1083
+ * Segment has an explicit author animation assignment (metadata panel save).
1084
+ * Backend-only emotion labels without author fields do not count.
1085
+ */
1086
+ declare function hasSegmentAnimationOverride(segment: WordAnimationFields | null | undefined): boolean;
1087
+ declare function clearWordAnimationFields<T extends WordAnimationFields>(word: T): T;
1088
+ declare function clearSegmentAnimationFields<T extends WordAnimationFields>(segment: T): T;
1089
+ declare function resetSubtitleToNormal<T extends WordAnimationFields & {
1090
+ words?: WordAnimationFields[];
1091
+ }>(subtitle: T): T;
1092
+ declare function subtitleHasAnyAnimationOverride(subtitle: WordAnimationFields & {
1093
+ words?: WordAnimationFields[];
1094
+ } | null | undefined): boolean;
1095
+ declare function getManualAnimationsStorageKey(videoId: string | null | undefined): string | null;
1096
+ declare function readManualAnimationsPreference(videoId: string | null | undefined): boolean;
1097
+ declare function writeManualAnimationsPreference(videoId: string | null | undefined, enabled: boolean): void;
1098
+ /**
1099
+ * "Manual soundbites only" mode: when enabled, auto-detected soundbites are
1100
+ * suppressed (no text, no animation) and only soundbites the author added by
1101
+ * hand (tagged `manual: true`) are shown. Mirrors the manual-animations pref.
1102
+ */
1103
+ declare function getManualSoundbitesStorageKey(videoId: string | null | undefined): string | null;
1104
+ declare function readManualSoundbitesPreference(videoId: string | null | undefined): boolean;
1105
+ declare function writeManualSoundbitesPreference(videoId: string | null | undefined, enabled: boolean): void;
1106
+ /** Clamp and round intensity to 0–1 (3 decimal places). */
1107
+ declare function clampAnimationIntensity(value: number): number;
1108
+ /**
1109
+ * Multiply author-set emotion_intensity on segments and words by `factor`.
1110
+ * Only touches overrides that already have an explicit intensity (GTS-independent).
1111
+ */
1112
+ declare function scaleAuthorAnimationIntensities<T extends WordAnimationFields & {
1113
+ words?: WordAnimationFields[];
1114
+ }>(subtitles: T[], factor: number): {
1115
+ segmentCount: number;
1116
+ wordCount: number;
1117
+ };
1118
+
1119
+ /**
1120
+ * Word-level expressive animation scheduling.
1121
+ *
1122
+ * When `ANIMATION_STYLING.wordAnimation.allowOverlap` is false, each word's
1123
+ * URL curve runs only after the previous word finishes — then returns to rest
1124
+ * (t = 0) before the next word begins.
1125
+ */
1126
+ interface WordTimingWindow {
1127
+ start: number;
1128
+ end: number;
1129
+ }
1130
+ interface SequentialWordExpressiveSlot {
1131
+ expressiveStart: number;
1132
+ expressiveDuration: number;
1133
+ }
1134
+ declare function getWordExpressiveDuration(word: WordTimingWindow): number;
1135
+ type WordExpressiveSchedule = Array<SequentialWordExpressiveSlot | null>;
1136
+ declare function buildSequentialExpressiveSchedule(words: WordTimingWindow[], shouldAnimate?: (word: WordTimingWindow, index: number) => boolean): WordExpressiveSchedule;
1137
+ declare function isWordAnimationOverlapAllowed(): boolean;
1138
+ /**
1139
+ * Progress along the authored URL curve (0–1).
1140
+ * Overlap allowed: progress follows backend word.start and holds at 1 after the curve completes.
1141
+ * Sequential: each word waits for the previous slot, then returns to 0 after its curve completes.
1142
+ */
1143
+ declare function calculateWordExpressiveProgress(currentTime: number, word: WordTimingWindow, slot: SequentialWordExpressiveSlot | null | undefined, allowOverlap?: boolean): number;
1144
+ declare function getSegmentAnimationPreviewTime(startTime: number | null | undefined, endTime: number | null | undefined): number;
1145
+ /**
1146
+ * Time (seconds) at the midpoint of a word's expressive URL curve — matches playback scheduling.
1147
+ */
1148
+ declare function getWordAnimationPreviewTime(words: WordTimingWindow[], wordIndex: number, options?: {
1149
+ shouldAnimate?: (word: WordTimingWindow, index: number) => boolean;
1150
+ allowOverlap?: boolean;
1151
+ }): number | null;
892
1152
 
893
1153
  /**
894
1154
  * Prosody Weight — Natural Voice Intonation for Animations
@@ -1506,4 +1766,4 @@ declare function logSubtitleData(data: unknown, meta?: {
1506
1766
  url?: string;
1507
1767
  }): void;
1508
1768
 
1509
- export { ANIMATION_STYLING, ANIMATION_URLS, AUTHORED_PLAYBACK_OPTIONS, type AnimationFetcher, type AnimationOptions, type AnimationParameterState, type AnimationParameterStates, type AnimationRecord, type AnimationState, type CurvePoint, EMOTION_ANIMATION_URLS, type Emotion, type EmotionSelectionResult, type EmotionStyle, type EmphasisEffect, type FontAxisConfig, type FontConfig, type JoyEffect, type Letter, type LoginResponse, type ParameterState, type ParameterStates, PhontClient, type PhontClientOptions, type PublishedAnimationResolver, REFERENCE_GTS, REFERENCE_INTENSITY, RENDERING_CONTROL, type RegisterResponse, type SentenceAnimationState, type StateCallback, type StrongEmphasisData, type Stylesheet, type SubtitleDebugEntry, type SubtitleDebugStore, type SubtitleEngineState, type SubtitleLine, SubtitleManager, type SubtitleSegment, type SubtitleState$1 as SubtitleState, SubtitleStateManager, type SubtitleTrack, type SubtitleWord, type VodMetadata, type VodState$1 as VodState, type Word, type WordAnimationState, type WordLetterSpacingParams, calculateAnimationParameters, calculateAnimationState, calculateDynamicWordSpacing, calculateEmphasisMultiplier, calculateGTSValues, calculateJoy, calculateJoyBulge, calculateNormalizedTime, calculateWeightFromVolume, calculateWidthFromSpeechRate, calculateWordEmphasisEffects, calculateWordLetterSpacing, capEmotionIntensity, computeProsodyWeight, createPublishedAnimationResolver, decodeAnimationUrl, ensureFont, findSubtitleForWord, generateTextShadow, getAnimationUrlForEmotion, getCombinedBlurAmount, getCurrentAuthToken, getCurrentSessionId, getFontFamilyCSS, getJoyAnimationMode, getJoyFilter, getJoyTransform, getMergedSubtitles, getMotionBlurAmount, getSubtitleAnimations, getSubtitleText, getSubtitleTiming, getSubtitleWords, getWordEmphasis, hasMergedSubtitles, hockeyStickIntensity, isInEmphasisRange, isInStrongEmphasisRange, isSubtitleDebugEnabled, logSubtitleData, meetsEmotionThreshold, preloadAnimationFonts, processEmotionsWithImportance, resolveEffectiveGts, sampleParameterCurve, selectEmotion, selectFontFamily, shouldUseAngryFont, shouldUseJoyFont, shouldUseSadnessFont, splitTextIntoLetters, subtitleManager };
1769
+ export { ANIMATION_STYLING, ANIMATION_URLS, AUTHORED_PLAYBACK_OPTIONS, type AnimationFetcher, type AnimationOptions, type AnimationParameterState, type AnimationParameterStates, type AnimationRecord, type AnimationState, type CurvePoint, EMOTION_ANIMATION_URLS, type Emotion, type EmotionSelectionResult, type EmotionStyle, type EmphasisEffect, type FontAxisConfig, type FontConfig, type InitialPlaylist, type InitialPlaylistListener, type JoyEffect, type Letter, type LiveSegmentSource, type LoginResponse, NORMAL_ANIMATION_EMOTIONS, type ParameterState, type ParameterStates, PhontClient, type PhontClientOptions, type PublishedAnimationResolver, REFERENCE_GTS, REFERENCE_INTENSITY, RENDERING_CONTROL, type RegisterResponse, type SegmentInfo, type SegmentListener, type SentenceAnimationState, type SequentialWordExpressiveSlot, type StateCallback, type StrongEmphasisData, type Stylesheet, type SubtitleDebugEntry, type SubtitleDebugStore, type SubtitleEngineState, type SubtitleLine, SubtitleManager, type SubtitleSegment, type SubtitleState$1 as SubtitleState, SubtitleStateManager, type SubtitleTrack, type SubtitleWord, type VodMetadata, type VodState$1 as VodState, type Word, type WordAnimationFields, type WordAnimationSource, type WordAnimationState, type WordExpressiveSchedule, type WordLetterSpacingParams, type WordTimingWindow, buildSequentialExpressiveSchedule, calculateAnimationParameters, calculateAnimationState, calculateDynamicWordSpacing, calculateEmphasisMultiplier, calculateGTSValues, calculateJoy, calculateJoyBulge, calculateNormalizedTime, calculatePerWordSpacing, calculateWeightFromVolume, calculateWidthFromSpeechRate, calculateWordEmphasisEffects, calculateWordExpressiveProgress, calculateWordLetterSpacing, capEmotionIntensity, clampAnimationIntensity, clearSegmentAnimationFields, clearWordAnimationFields, computeProsodyWeight, createBitmovinLiveSegmentSource, createHlsLiveSegmentSource, createLiveSegmentSource, createPublishedAnimationResolver, createShakaLiveSegmentSource, decodeAnimationUrl, ensureFont, findSubtitleForWord, generateTextShadow, getAnimationUrlForEmotion, getCombinedBlurAmount, getCurrentAuthToken, getCurrentSessionId, getFontFamilyCSS, getJoyAnimationMode, getJoyFilter, getJoyTransform, getManualAnimationsStorageKey, getManualSoundbitesStorageKey, getMergedSubtitles, getMotionBlurAmount, getSegmentAnimationPreviewTime, getSubtitleAnimations, getSubtitleText, getSubtitleTiming, getSubtitleWords, getWordAnimationPreviewTime, getWordEmphasis, getWordExpressiveDuration, hasMergedSubtitles, hasSegmentAnimationOverride, hasWordAnimationOverride, hockeyStickIntensity, isInEmphasisRange, isInStrongEmphasisRange, isNormalAnimationEmotion, isSubtitleDebugEnabled, isWordAnimationOverlapAllowed, logSubtitleData, meetsEmotionThreshold, preloadAnimationFonts, processEmotionsWithImportance, readManualAnimationsPreference, readManualSoundbitesPreference, resetSubtitleToNormal, resolveEffectiveGts, resolveWordAnimationSource, sampleParameterCurve, scaleAuthorAnimationIntensities, selectEmotion, selectFontFamily, shouldUseAngryFont, shouldUseJoyFont, shouldUseSadnessFont, splitTextIntoLetters, subtitleHasAnyAnimationOverride, subtitleManager, writeManualAnimationsPreference, writeManualSoundbitesPreference };