@fretfall/player 0.2.1 → 0.3.0

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.
package/README.md CHANGED
@@ -45,14 +45,56 @@ fretfall.part = 1;
45
45
  | Member | |
46
46
  |:--|:--|
47
47
  | `open(files, options)` / `pick()` | Open songs, or show the file dialog |
48
- | `playing`, `time`, `length` | Where playback is, in seconds. `playing` is settable: it waits for the synth's instruments |
48
+ | `playing`, `time`, `length` | Where playback is, in seconds. `playing` is settable: it waits for the synth's instruments. So is `time`: a jump to there, kept within the song |
49
49
  | `parts`, `part` | The song's parts, and the one shown (settable) |
50
+ | `notes` | What the part shown asks for: the open strings, and each note's time, string, fret and midi note. A copy each read |
51
+ | `speed` | How fast it plays, 1 being the song's own tempo. Settable, in the player's steps of a tenth from 0.1 to 1.5 |
52
+ | `style` | The look: note shape, colour set, fonts, string colours, headstock. Settable whole or in part |
50
53
  | `addFormat({ name, extensions, open })` | Read another file type: `open(file)` resolves to `{ song, audio }` |
51
54
  | `closeSheets()` | Close Settings and the notation sheet |
55
+ | `dock(element, more?)` | Mounted in a page: the header's controls in an element of the page's own, see below |
52
56
 
53
57
  Events on `window`: `fretfall:ready`, `fretfall:song`, `fretfall:playing`, `fretfall:sheet`. The modules import on their own
54
58
  too, for example `music.js` for tunings and note names.
55
59
 
60
+ ### In a page of your own
61
+
62
+ A page that isn't the player's, a React app's say, mounts it in an element instead. `mount.js` is written from the player's
63
+ page by the build, so it carries the same markup and styles, kept to that element:
64
+
65
+ ```js
66
+ import { mount } from '@fretfall/player/mount.js';
67
+
68
+ const fretfall = await mount(element); // window.fretfall, once fretfall:ready has fired
69
+ ```
70
+
71
+ - **Once a page.** The player's modules run once and there is no unmount: a second call returns the first one's promise. Keep
72
+ the element and hide it (`hidden`, `display: none`) rather than removing it; hidden, the player draws nothing and leaves
73
+ the keys alone. It plays on, so pause it first: `fretfall.playing = false`.
74
+ - **The element needs a size**, a height above all: the player fills it, whether that is the whole screen or a hero. Inside,
75
+ it is a box of its own (`contain: layout`): its bar and sheets stay in it, and full screen is that box's.
76
+ - **The ids in the player are its own** — `play`, `open`, `menu`, `settings`, `file`, `fonts` and a hundred more — so the page
77
+ around it must not use them; `mount()` rejects if it finds one taken. Its small-screen layouts still follow the window's
78
+ width, not the element's.
79
+ - The page around it stays the page's: its styles, its title (follow `fretfall:song` to set one), keys pressed in its inputs
80
+ and on its buttons, and files dropped outside the player. With the focus nowhere, the shortcuts are the player's. Band
81
+ windows open the page's own URL with `?band=`, so that URL has to mount the player again.
82
+
83
+ #### One bar: the player's controls in the page's own
84
+
85
+ A page with a bar of its own has two once the player is in it. `fretfall.dock(element)` moves the header's controls — the
86
+ part picker, time, speed, volume, loop, play, open, help, settings and full screen — into `element`, and hides the player's
87
+ header while they are there, so the highway starts at the top of its element. They are the player's own buttons, styled
88
+ by its stylesheet: `element` is marked `data-fretfall` (and `data-fretfall-dock`) so that reaches it, in its own colours
89
+ and fonts rather than the theme's — set the variables it draws with (`--chip`, `--chip-border`, `--ink`, `--text`,
90
+ `--muted`, `--accent`, `--ui`, `--num`) on the element for your bar's, and hide or restyle what your bar does differently
91
+ under that attribute. `fretfall.dock(element, more)` puts help, settings and full screen into `more` instead, for a bar
92
+ with a right side of its own. The tooltips and the volume slider open under the buttons, where they stand now.
93
+ `fretfall.dock(null)` brings everything home, and a page removing its bar has to call it first, or the controls go with
94
+ it (`demo/mount.html` shows a dock).
95
+
96
+ Types come with it (`mount.d.ts`): `mount()`, the `fretfall` hook and its events.
97
+
56
98
  Keys: <kbd>Space</kbd> play · <kbd>L</kbd> loop · <kbd>O</kbd> open · <kbd>D</kbd> 2D tab · <kbd>K</kbd> metronome ·
57
99
  <kbd>F</kbd> full screen · <kbd>S</kbd> settings · <kbd>?</kbd> everything else. Add `?perf` to the URL for a frame profiler.
58
100
 
@@ -71,6 +113,9 @@ npm run bench # frame time, draw calls, sync and size of dist/
71
113
  into `dist/`, which is what npm publishes and what the demo serves — so the page next to the modules, as a page built on the
72
114
  player has it. The front door, between `<!-- demo -->` and `<!-- /demo -->` in the page, stays out of the package.
73
115
 
116
+ `demo/mount.html` tries the mounted player, in a page with a look and an input of its own. `mount.js` only exists once built,
117
+ so it is served from the built demo: `DEMO=1 npm run build && npx serve dist`, then `/mount.html`.
118
+
74
119
  No pull request may make the player slower or bigger. CI builds it and the base branch, benchmarks both in turns on the same
75
120
  runner, and fails on more than 10% frame or sync time, 5% draw calls or 1% gzipped size. A regression taken on purpose
76
121
  passes with the `perf-ok` label.
package/highway.js CHANGED
@@ -1 +1 @@
1
- import{lap as ue}from"./perf.js";import{noteName as $i}from"./music.js";const Ot=900,Li=84,Jn=28,Vn=2.2,Di=.9,Ci=2.4,Ri=a=>Li*(a.drawDistance??1)/(Jn*(a.noteSpeed??1)),_i=.34,$t=24,fn=1.2,Ei=1.25,Oi=1.25,Re=5,cn=1,Bi=1.6,Hi=2,dn=.19,Zn=.12,Qn=3,Ni=11,Fi=[{time:-1/0,endTime:1/0,fret:1,width:4}],Cn=[3,5,7,9,12,15,17,19,21,24],Rn=.15,ti=.31,ei=1.7,ni=1.4,ii=1,oi=1.2,zi=.75,ai=(a,l,f,o,e)=>{const[M,m,d,t]=[Math.min(a,l),Math.max(a,l),Math.min(f,o),Math.max(f,o)],L=Math.min(e,(m-M)/2,(t-d)/2),R=(Tt,U,wt)=>{const _=Array.from({length:5},(xt,st)=>[Tt+Math.cos(wt+st*Math.PI/8)*L,U+Math.sin(wt+st*Math.PI/8)*L]);return[_[0],..._,_[4]]};return[...R(m-L,t-L,0),...R(M+L,t-L,Math.PI/2),...R(M+L,d+L,Math.PI),...R(m-L,d+L,1.5*Math.PI)]},Gi=a=>[...a,a.at(-1),...a.slice(0,-1).reverse().map(([l,f])=>[l,-f])],Ui={inline:{label:"6 in line",outline:[[0,1],[.42,1.05],[.73,1.3],[1.01,1.53],[1.46,1.45],[2.73,1.08],[4.38,.62],[5.79,.17],[6.54,-.13],[6.88,-.35],[7.03,-.88],[6.98,-1.56],[6.64,-2.11],[6.14,-2.38],[5.59,-2.34],[5.21,-2.05],[4.99,-1.66],[4.75,-1.39],[4.25,-1.3],[3.5,-1.39],[2.6,-1.6],[1.85,-1.81],[1.18,-1.75],[.83,-1.36],[.47,-1.06],[0,-1]],posts:{from:[1.56,.95],to:[6.01,-.58]},keys:"machine",tree:2.47},fourTwo:{label:"4 + 2",outline:[[0,1],[.48,1.03],[.94,1.35],[1.21,1.72],[1.52,1.72],[2.99,1.31],[4.23,.95],[5.53,.57],[5.92,.28],[6.07,-.36],[6.05,-1.03],[5.79,-1.53],[5.36,-1.67],[4.95,-1.53],[4.68,-1.29],[4.36,-1.19],[4.02,-1.32],[3.67,-1.56],[2.99,-1.67],[2.08,-1.6],[1.4,-1.43],[.94,-1.16],[.48,-1.03],[0,-1]],posts:{from:[1.81,1.08],to:[4.94,-.03],treble:{share:1/3,from:[2.33,-1.03],to:[3.38,-.69]}},keys:"machine"},openBook:{label:"3 + 3 open book",outline:Gi([[0,1],[.48,1.07],[.96,1.33],[1.47,1.53],[3.16,1.67],[4.98,1.76],[6.25,1.8],[6.25,1.8],[6.42,.93],[6.3,0]]),posts:{from:[2.5,1.07],to:[5.1,1.07],treble:{share:1/2}},keys:"tulip",cover:[[.22,0],[.22,.4],[.36,.5],[.78,.4],[1.3,.25],[1.82,.16],[2.13,.1],[2.24,0],[2.13,-.1],[1.82,-.16],[1.3,-.25],[.78,-.4],[.36,-.5],[.22,-.4],[.22,0]],screws:[[.43,0],[1.98,0]]},pointed:{label:"3 + 3 pointed",outline:[[0,1],[.36,1.12],[.75,1.47],[1.07,1.84],[1.38,1.93],[2.29,1.73],[3.26,1.55],[4.36,1.35],[5.45,1.12],[5.75,.95],[5.86,.43],[5.98,-.22],[6.29,-.75],[6.75,-1.22],[6.75,-1.22],[6.17,-1.24],[5.33,-1.3],[4.36,-1.37],[3.26,-1.55],[2.29,-1.73],[1.38,-1.93],[1.07,-1.84],[.75,-1.47],[.36,-1.12],[0,-1]],posts:{from:[2.07,1],to:[4.65,.46],treble:{share:1/2}},keys:"machine",cover:[[.1,.44],[.1,.44],[.59,.4],[1.1,.28],[1.69,0],[1.69,0],[1.1,-.28],[.59,-.4],[.1,-.44],[.1,-.44],[.1,.44]],screws:[]},headless:{label:"Headless",outline:ai(.2,.95,-1.06,1.06,.2),clamps:.58}};function Yi(a,l){const f=l.length,o=ri(a.outline,10);let e=l.map(t=>[a.clamps,t]),M=l.map(()=>1);if(a.posts){const{from:t,to:L,treble:R}=a.posts,Tt=R?Math.floor(f*R.share+1e-9):0,U=f-Tt,wt=(Ht,dt,E)=>j=>Ht.map(($,P)=>$+(dt[P]-$)*j/Math.max(1,E-1)),_=([Ht,dt])=>[Ht,-dt],xt=wt(t,L,U),st=wt(R?.from??_(t),R?.to??_(L),Tt);e=l.map((Ht,dt)=>dt<U?xt(dt):st(f-1-dt)),M=l.map((Ht,dt)=>dt<U?1:-1)}const m=(t,L)=>{let R=null;for(let Tt=1;Tt<o.length;Tt++){const[U,wt]=o[Tt-1],[_,xt]=o[Tt];if((U-t)*(_-t)>0||U===_)continue;const st=wt+(xt-wt)*(t-U)/(_-U);(R===null||st*L>R*L)&&(R=st)}return R??L},d=a.keys?e.map(([t],L)=>({u:t,side:M[L],edge:m(t,M[L])})):[];return{outline:o,ends:e,keys:d}}const si=new WeakMap,Ye=new Map,qi=(a,l)=>{const f=l.join(),o=si.get(a);if(o?.key===f)return o.parts;const e=Yi(a,l);return si.set(a,{key:f,parts:e}),e},li=(a,l)=>(Ye.has(a)||(Ye.size>500&&Ye.clear(),Ye.set(a,l())),Ye.get(a)),ri=(a,l=8)=>[...a.slice(0,-1).flatMap((f,o)=>{const e=a[Math.max(0,o-1)],M=a[o+1],m=a[Math.min(a.length-1,o+2)];return f[0]===M[0]&&f[1]===M[1]?[f]:Array.from({length:l},(d,t)=>{const L=t/l;return[0,1].map(R=>.5*(2*f[R]+(M[R]-e[R])*L+(2*e[R]-5*f[R]+4*M[R]-m[R])*L*L+(3*f[R]-e[R]-3*M[R]+m[R])*L**3))})}),a.at(-1)],_n=(a,l)=>{if(!a.startsWith("#"))return a;const f=o=>{const e=parseInt(a.slice(o,o+2),16);return Math.round(l>0?e+(255-e)*l:e*(1+l)).toString(16).padStart(2,"0")};return`#${f(1)}${f(3)}${f(5)}`},mn=new Map,I=(a,l)=>{if(!a.startsWith("#"))return a;const f=a+l;let o=mn.get(f);return o||(mn.size>1e3&&mn.clear(),mn.set(f,o=`rgba(${parseInt(a.slice(1,3),16)}, ${parseInt(a.slice(3,5),16)}, ${parseInt(a.slice(5,7),16)}, ${l})`)),o},_e=(a,l)=>{let f=0,o=a.length;for(;f<o;){const e=f+o>>1;a[e].time<l?f=e+1:o=e}return f};function hi(a){if(a.links?.next.length===a.notes.length)return a.links;const l=a.notes.length,f=new Array(l).fill(-1),o=new Array(l).fill(-1),e={};let M=0;for(let m=0;m<l;m++){const{string:d,sustain:t}=a.notes[m];e[d]!==void 0&&([o[m],f[e[d]]]=[e[d],m]),e[d]=m,M=Math.max(M,t)}return a.links={next:f,prev:o,held:M}}const Me=a=>Math.round(a*4)/4,Bt=32,gn=new Map;let fi=0;const Jt=(a,l,f)=>{let o=gn.get(l);o||gn.set(l,o=new Map);let e=o.get(f);if(!e){++fi>5e3&&([fi,o]=[0,new Map],gn.clear(),gn.set(l,o)),a.font=l;const M=a.measureText(f);o.set(f,e={width:M.width,middle:(M.actualBoundingBoxAscent-M.actualBoundingBoxDescent)/2})}return e},pn=128,En=new WeakMap,Xi=a=>{if(!En.has(a)){const l=new OffscreenCanvas(1,pn),f=l.getContext("2d"),[o,e]=[a.floor0,a.floor1].map(m=>[1,3,5].map(d=>parseInt(m.slice(d,d+2),16))),M=Array.from({length:pn},(m,d)=>{const t=(d+.5)/pn;return`rgba(${o.map((L,R)=>Math.round(L+(e[R]-L)*t))}, ${1-t})`});M.forEach((m,d)=>{f.fillStyle=m,f.fillRect(0,pn-1-d,1,1)}),En.set(a,{strip:l,near:M[0]})}return En.get(a)},Ee=new Map,ci=new WeakMap,di=(a,l,f)=>{let o=ci.get(a);o||ci.set(a,o=new Map);let e=o.get(l);if(!e){e=a.createLinearGradient(0,0,0,1);for(const[M,m]of f)e.addColorStop(M,m);o.set(l,e)}return e},un=new Map,mi=(a,l,f,o,e)=>{const M=`${l}|${f}|${o}|${e}`;let m=un.get(M);return m||(un.size>20&&un.clear(),m=a.createLinearGradient(0,l,0,f),m.addColorStop(0,o),m.addColorStop(1,e),un.set(M,m)),m},Mn=(a,l)=>[a[0]-l[0],a[1]-l[1],a[2]-l[2]],xn=(a,l)=>a[0]*l[0]+a[1]*l[1]+a[2]*l[2],ji=(a,l)=>[a[1]*l[2]-a[2]*l[1],a[2]*l[0]-a[0]*l[2],a[0]*l[1]-a[1]*l[0]],Ki=a=>a.map(l=>l/Math.hypot(...a)),Ji=(a,l)=>{let f=0;for(const o of a??[]){if(o.time>l)break;f=o.fret}return f},qe=(a,l)=>{let f=0,o=a.length;for(;f<o;){const e=f+o>>1;a[e].time<=l?f=e+1:o=e}return a[Math.max(0,f-1)]},gi=a=>a*a*(3-2*a),Vi=.3,pi=new WeakMap;function ui(a,l){let f=pi.get(a);if(f||pi.set(a,f={}),!(l in f)){const o=Math.max(a.sustain,.05),M=(a[l]??(l==="bendCurve"&&a.bend?[[0,0],[.25,a.bend]]:null))?.map(([m,d])=>[m*o,d,!1])??[];M.length&&M[0][0]>.001&&(M[0][2]=!0,M.unshift([0,0,!1])),f[l]=M.length?M:null}return f[l]}function Mi(a,l){if(!a)return 0;let f=a[0][1];for(let o=1;o<a.length&&l>a[o-1][0];o++){const[[e,M],[m,d,t]]=[a[o-1],a[o]],L=Math.min(m-e,Vi)||1e-6;f=M+(d-M)*gi(Math.min(1,Math.max(0,(l-(t?m-L:e))/L)))}return f}const Zi=(a,l)=>Mi(ui(a,"bendCurve"),l),Qi=(a,l)=>Mi(ui(a,"whammy"),l),xi=new WeakMap,Oe=a=>{let l=xi.get(a);return l===void 0&&xi.set(a,l=Math.max(a.bend||0,...(a.bendCurve??[]).map(([,f])=>f))),l};function to(a){if(a.chordSpans)return a.chordSpans;const l=[];for(const f of a.chords){const o=Math.max(f.time+.25,...f.notes.map(M=>a.notes[M].time+a.notes[M].sustain)),e=l.at(-1);e&&f.time-e.end<1&&(f.name?f.name===e.name:f.highDensity)?e.end=Math.max(e.end,o):f.name&&l.push({name:f.name,time:f.time,end:o})}for(const f of a.handShapes??[])f.arpeggio&&f.name&&l.push({name:f.name,time:f.startTime,end:f.endTime});return a.chordSpans=l.sort((f,o)=>f.time-o.time)}function eo(a){if(a.chordRails)return a.chordRails;const l=[],f=o=>Math.max(o.time+.15,...o.notes.map(e=>a.notes[e].time+a.notes[e].sustain));for(let o=0;o<a.chords.length;o++){const e=a.chords[o];if(e.highDensity)continue;let M=f(e),m=o+1;for(;a.chords[m]?.highDensity&&a.chords[m].time-M<1;m++)M=Math.max(M,f(a.chords[m]));M=Math.min(M,a.chords[m]?.time??1/0),M-e.time>.2&&l.push({time:e.time,end:M,frets:e.notes.map(d=>a.notes[d].fret)})}for(const o of a.handShapes??[])o.arpeggio&&l.push({time:o.startTime,end:o.endTime,frets:o.frets,arpeggio:o});return a.chordRails=l}const bi={artificial:"AH",pinch:"PH",tap:"TH",semi:"SH",feedback:"FH"},yi=a=>a<.5?"¼":a===.5?"½":a===1?"full":a%1?`${Math.floor(a)}½`:String(a),Si=(a,l,f,o)=>{if(a===void 0)return l;const e=a+(l-a)*(1-Math.exp(-f/o));return Math.abs(l-e)<1e-6?l:e};function ki(a,l,f,o,e){a[l]===void 0&&([a[l],a[l+"Speed"]]=[f,0]);const M=2/o,m=M*e,d=1/(1+m+.48*m*m+.235*m*m*m),t=a[l]-f,L=(a[l+"Speed"]+M*t)*e;a[l+"Speed"]=(a[l+"Speed"]-M*L)*d,a[l]=f+(t+L)*d,Math.abs(a[l]-f)<1e-6&&Math.abs(a[l+"Speed"])<1e-6&&([a[l],a[l+"Speed"]]=[f,0])}function Ti(a,l,f=0){let o=1/0,e=-1/0;for(const m of a)m.endTime<=l||m.time>=l+Qn||(o=Math.min(o,m.fret-1),e=Math.max(e,m.fret-1+m.width));if(o===1/0){const m=qe(a,l);[o,e]=[m.fret-1,m.fret-1+m.width]}f&&(o=Math.min(o,f-1));const M=Math.max(Ni,e-o+2)+1;return{lo:o,hi:e,span:M,center:Math.min(25-M/2,Math.max(M/2-1,(o+e)/2))}}function no(a,l,f,o,e=0){const M=Ti(l,f,e),m=a.target,d=!m||M.lo<m.center-m.span/2||M.hi>m.center+m.span/2,t=m&&m.span-Math.max(M.span,Ti(l,f+Qn,e).span)>2;(d||t)&&(a.target=M);const L=Math.min(o-(a.at??o),100);a.at=o,ki(a,"span",a.target.span,a.target.span>a.span?.8:1.4,L/1e3),ki(a,"center",a.target.center,1,L/1e3);const R=qe(l,f);return a.left=Si(a.left,R.fret-1,L,90),a.right=Si(a.right,R.fret-1+R.width,L,90),R}function Pi(a,l,f,o,e,M,m,d){a.beginPath(),a.moveTo(l-o,f-M*e),a.lineTo(l,f),a.lineTo(l+o,f-M*e),a.lineWidth=Math.max(3,e*1.15),a.strokeStyle=d,a.stroke(),a.lineWidth=Math.max(1.5,e*.65),a.strokeStyle=m,a.stroke(),a.lineWidth=Math.max(.6,e*.2),a.strokeStyle="rgba(255, 255, 255, 0.5)",a.stroke()}function Xe(a,l,f,o,e){a.beginPath(),a.moveTo(l,f),a.lineTo(o,e),a.stroke()}function Ai(a){const l=devicePixelRatio||1,f=a.clientWidth,o=a.clientHeight;(a.width!==Math.round(f*l)||a.height!==Math.round(o*l))&&(a.width=Math.round(f*l),a.height=Math.round(o*l));const e=a.getContext("2d"),M=o/Ot,m=f/M,d=l*M;return e.setTransform(d,0,0,d,0,0),e.clearRect(0,0,m,Ot),{g:e,W:m,B:d}}function ho(a,l,f,o,e){const{g:M,W:m,B:d}=Ai(a);let t=M;if(!l)return;const L=l.anchors.length?l.anchors:Fi,R=Ji(l.capos,f),Tt=no(e,L,f,performance.now(),R),U=l.strings,wt=Math.min(.5,5*_i/Math.max(1,U-1)),_=wt*Oi*(o.boardHeight??1),xt=_*(U-1),st=n=>(o.stringOrder==="high"?n:U-1-n)*_,Ht=n=>(n>=U/2?1:-1)*(o.stringOrder==="high"?-1:1),dt=Jn*(o.noteSpeed??1),E=Ri(o),j=-.22,$=xt+.22,P=j-.06,Nt=E*dt,ct=n=>Math.max(0,n)*dt,Ft=n=>o.str[n%o.str.length],Lt=o.noteLines===0?null:`rgba(255, 255, 255, ${o.noteLines??.5})`,he=+o.fretNumbers||0,Vt=e.span,vt=[e.center,wt*(U-1)/2,0],we=(o.viewAngle??30)*Math.PI/180,He=.6*Math.SQRT2*Vt,je=[vt[0],xt+He*Math.sin(we),-He*Math.cos(we)],w=Ki(Mn([vt[0],0,2.2*Vt],je)),Q=ji(w,[1,0,0]),V=(o.sideAngle??0)*Math.PI/180,[bt,Ct]=[Math.sin(V),Math.cos(V)],te=Mn(je,vt),zt=xn(te,w),ve=xn(te,Q),Rt=[-bt,w[1]*Ct,w[2]*Ct],be=[Ct,w[1]*bt,w[2]*bt],Gt=[vt[0]+ve*Q[0]+zt*Rt[0],vt[1]+ve*Q[1]+zt*Rt[1],ve*Q[2]+zt*Rt[2]],Ke=Math.min(m*.88,Ot*(o.fill?1.3:1.05)),Je=Ke*xn(Mn(vt,Gt),Rt)/Vt,mt=Math.min(Ei*(o.fretWidth??1),m*Vt/(Ke*Math.max(1,Vt-2.5)));let Ve=0,Ne=0;const[bn,yn,Ze]=Gt,[Fe,ye,Sn]=Rt,[Se,kn,Qe]=be,[Tn,tn,en]=Q,v=(n,i,h)=>{const s=n-bn,r=i-yn,g=h-Ze,u=Je/Math.max(.05,s*Fe+r*ye+g*Sn);return[m/2+(s*Se+r*kn+g*Qe)*mt*u+Ve,Ot/2-(s*Tn+r*tn+g*en)*u+Ne,u]},[nn,on,p]=v(...vt);[Ve,Ne]=[m/2-nn,Ot*(o.fill?.83:.81)-on];const[,c]=v(e.center-Vt/2,P,0),[,D]=v(e.center+Vt/2,P,0),[,gt]=v(e.center,P,0);Ne-=Math.min(Ot*.08,Math.max(0,c-gt,D-gt)),ue("setup");const A=(n,i=!0)=>{t.beginPath();for(let h=0;h<n.length;h++){const[s,r]=v(n[h][0],n[h][1],n[h][2]);h?t.lineTo(s,r):t.moveTo(s,r)}i&&t.closePath()},H=(n,i)=>{A([n,i],!1),N()},Pt=(n,i,h,s,r)=>{if(o.gem!=="pill")return A([[n-s,i-r,h],[n+s,i-r,h],[n+s,i+r,h],[n-s,i+r,h]]);const[g,u]=v(n-s,i,h),[S,x]=v(n+s,i,h),[,k]=v(n,i+r,h),[,J]=v(n,i-r,h),F=Math.atan2(x-u,S-g),z=Math.min(Math.abs(J-k),Math.hypot(S-g,x-u))/2,[W,O]=[z*Math.cos(F),z*Math.sin(F)];t.beginPath(),t.arc(g+W,u+O,z,F+Math.PI/2,F+Math.PI*1.5),t.arc(S-W,x-O,z,F-Math.PI/2,F+Math.PI/2),t.closePath()},rt=(n,i)=>{const h=qe(L,i),s=n.filter(r=>r>0);return[Math.min(h.fret-1,...s.map(r=>r-1))+.05,Math.max(h.fret-1+Math.max(4,h.width),...s)-.05]},fe=(n,i,h,s,r)=>{H([n-s,i-r,h],[n+s,i+r,h]),H([n-s,i+r,h],[n+s,i-r,h])},We=o.markings==="white",Zt=We?"#ffffff":o.ink,Ie=(n,i,h,s,r,g,u,S=null)=>{const[x,k]=u?[r*.85,g*.8]:[Math.min(r,.34)*.4,g*.55],J=u&&!We&&!S;S||(t.strokeStyle=I(o.ink,J?.85:.7),t.lineWidth=J?Math.max(2,.06*s):Math.max(3.5,.1*s),fe(n,i,h,x,k)),!J&&(t.strokeStyle=S??"#ffffff",t.lineWidth=Math.max(S?2:1.8,.05*s),fe(n,i,h,x,k))};let Qt=null,_t=0;const ke=n=>{n!==Qt&&(t.font=Qt=n)},ce={},oe=(n,i,h,s,r,g)=>{const u=ce[r]??=`${r} ${Bt}px ${o.num}`,S=s/Bt;return Jt(t,u,n),ke(u),t.textAlign=g,t.setTransform(d*S,0,0,d*S,d*i,d*(h-_t)),Jt(t,u,n).middle},Ut=()=>t.setTransform(d,0,0,d,0,-d*_t),ze=(n,i,h)=>{t.fillStyle=n,t.setTransform(d,0,0,d*(h-i),0,d*(i-_t)),t.fill(),Ut()},yt=(n,i,h,s,r,g,u=700,S="center",x=!0,k=!1)=>{const[J,F,z]=v(i,h,s),W=r*(k?z:Math.sqrt(z*p));if(W<(k?1:8)||J<-60||J>m+60)return;t.textBaseline="alphabetic";const O=oe(n,J,F,W,u,S);x&&(t.lineWidth=Bt*.2,t.strokeStyle=I(o.ink,.9),t.strokeText(n,0,O)),t.fillStyle=g,t.fillText(n,0,O),Ut(),t.textBaseline="middle"},ee=(n,i,h,s,r,g,u=700)=>{const[S,x,k]=v(i,P,h),J=(p/k)**zi,[F,z]=v(i+s*J,P,h),W=Math.hypot(F-S,z-x);let O=r*J,[lt,nt]=v(i,P,h+O),X=Math.hypot(lt-S,nt-x);for(let et=0;et<3&&X>W*oi;et++)O*=W*oi/X,[lt,nt]=v(i,P,h+O),X=Math.hypot(lt-S,nt-x);const at=Math.abs(Math.atan2(lt-S,x-nt));if(S<-60||S>m+60||X<ii||at>ni)return;const b=t.globalAlpha;t.globalAlpha=b*Math.min(1,(ni-at)/.2,(X-ii)/3);const kt=ce[u]??=`${u} ${Bt}px ${o.num}`;ke(kt),t.textAlign="center",t.textBaseline="alphabetic";const{middle:It}=Jt(t,kt,n);t.setTransform(d*(F-S)/Bt,d*(z-x)/Bt,-d*(lt-S)/Bt,-d*(nt-x)/Bt,d*S,d*(x-_t)),t.fillStyle=g,t.fillText(n,0,It),Ut(),t.globalAlpha=b,t.textBaseline="middle"},[,pt]=v(vt[0],P,0),[,$e]=v(vt[0],P,Nt),Wt=(n,i,h)=>{const s=`${pt}|${$e}`;(Ee.span!==s||Ee.size>300)&&(Ee.clear(),Ee.span=s);const r=`${n}|${i}|${h}`;let g=Ee.get(r);return g||(g=t.createLinearGradient(0,pt,0,$e),g.addColorStop(0,I(n,i)),g.addColorStop(1,I(n,h)),Ee.set(r,g)),g};let Yt=null;const tt=(n,i,h=10,s=!1)=>Yt=n?{color:i,blur:h,faded:s}:null,Pn=[[.6,.05],[.35,.13],[.15,.27]],de=[[.4,.3]],ae=n=>{if(!Yt)return;const{lineWidth:i,globalAlpha:h}=t,s=n?1:Math.min(1,2*i/Yt.blur);t.save(),t.strokeStyle=Yt.faded?Wt(Yt.color,1,.1):Yt.color;for(const[r,g]of Yt.blur>4?Pn:de)t.lineWidth=(n?0:i)+2*Yt.blur*r,t.globalAlpha=h*g*s,t.stroke();t.restore()},N=()=>{ae(!1),t.stroke()},Y=()=>{ae(!0),t.fill()};t.textBaseline="middle",t.lineCap="round",t.lineJoin="round";const{strip:se,near:B}=Xi(o);let[ot,ft]=[-60,$t+60];if(V){const n=vt[0]+(1-xn(Mn([vt[0],P,0],Gt),Rt))/Rt[0];[ot,ft]=Rt[0]>0?[Math.max(-60,n),$t+60]:[-60,Math.min($t+60,n)]}t.save(),A([[ot,P,0],[ft,P,0],[ft,P,Nt],[ot,P,Nt]]),t.clip(),V&&(t.fillStyle=B,t.fillRect(0,pt,m,Ot-pt)),t.imageSmoothingEnabled=!1,t.drawImage(se,0,$e,m,pt-$e),t.restore();const ut=(n,i)=>{const[h,s]=v(...n),[r,g]=v(...i);t.moveTo(h,s),t.lineTo(r,g)};t.strokeStyle=Wt(o.lane,.5,.04),t.lineWidth=Di,t.beginPath();for(let n=0;n<=$t;n++)ut([n,P,0],[n,P,Nt]);N();for(const n of[!1,!0]){t.strokeStyle=n?o.measure:o.beat,t.lineWidth=n?1.6:1,t.beginPath();const i=[];for(let h=_e(l.beats,f);h<l.beats.length;h++){const s=l.beats[h],r=s.time-f;if(r>E)break;s.measure>=0===n&&(r>E-.4?i.push(r):ut([0,P,ct(r)],[$t,P,ct(r)]))}N();for(const h of i)t.globalAlpha=(E-h)/.4,t.beginPath(),ut([0,P,ct(h)],[$t,P,ct(h)]),N();t.globalAlpha=1}if(he)for(let n=_e(l.beats,f);n<l.beats.length;n++){const i=l.beats[n],h=i.time-f;if(h>E)break;if(i.measure<0)continue;const s=qe(L,i.time),r=ct(h);t.globalAlpha=Math.min(1,(E-h)/.4);for(const g of Cn)(g<s.fret||g>=s.fret+s.width)&&ee(String(g),g-.5,r,ti,ei,I(o.inlay,he))}t.globalAlpha=1,(o.guides===!1?[]:L.filter(n=>n.endTime>f&&n.time<f+E)).forEach((n,i)=>{const h=ct(Math.max(0,n.time-f)),s=ct(Math.min(E,n.endTime-f)),r=n.fret-1,g=r+n.width;t.fillStyle=Wt(o.anchorFill,o.anchorOpacity,.02),A([[r,P,h],[g,P,h],[g,P,s],[r,P,s]]),Y(),t.strokeStyle=Wt(o.anchorLane,.55,.04),t.lineWidth=Ci*.6;for(const u of[r,g])H([u,P,h],[u,P,s]);i&&n.time>f&&H([r,P,h],[g,P,h]),i&&n.time>f+.3&&yt(String(n.fret),r-.2,P,h,.3,o.anchorLane,700,"right")});const Te=new Map,ie=n=>{const i=Math.round(n*100);return Te.has(i)||Te.set(i,{dt:n-f,texts:[],pins:[]}),Te.get(i)};for(const n of l.markers??[])n.time>=f&&n.time<=f+E&&!ie(n.time).texts.includes(n.text)&&ie(n.time).texts.push(n.text);for(const n of l.hairpins??[])n.time>=f&&n.time<=f+E&&ie(n.time).pins.push(n.kind);const vi=Math.min(e.center-(e.span/2+.5)/mt,-.5);for(const{dt:n,texts:i,pins:h}of Te.values()){const[s,r,g]=v(vi,P,ct(n)),u=Math.sqrt(g*p),S=i.join(" · "),x=.25*u,k=`700 ${Bt}px ${o.num}`,J=.3*u/Bt,F=S?Jt(t,k,S).width*J:0,z=F+h.length*(.9*u+x);ke(k);let W=Math.max(s-.3*u,16+z);t.globalAlpha=Math.min(1,(E-n)/.4),S&&(t.save(),t.translate(W,r),t.scale(J,J),t.textAlign="right",t.lineWidth=Bt*.2,t.strokeStyle=I(o.ink,.9),t.strokeText(S,0,0),t.fillStyle=o.accent,t.fillText(S,0,0),t.restore(),W-=F+x);for(const O of h){const lt=W-.9*u,nt=.14*u,[X,at]=O==="cresc"?[lt,W]:[W,lt];for(const[b,kt]of[[I(o.ink,.9),Math.max(3.5,.12*u)],[o.text,Math.max(1.5,.05*u)]])t.strokeStyle=b,t.lineWidth=kt,t.beginPath(),t.moveTo(at,r-nt),t.lineTo(X,r),t.lineTo(at,r+nt),N();W=lt-x}}t.globalAlpha=1,ue("floor");const qt=[];for(let n=_e(l.notes,f-hi(l).held-.3);n<l.notes.length;n++){const i=l.notes[n];if(i.time>f+E)break;const h=Math.max(i.sustain,(i.slideTo??i.slideUnpitchTo??null)===null?0:.25,.15);i.time+h>=f-.05&&qt.push(i)}const me=n=>n.chord===null||n.chord===void 0?null:l.chords[n.chord],An=n=>o.repeatMarks==="frame"&&(n.repeat||me(n)?.highDensity),ge=n=>{const i=qe(L,n.time),h=n.fret===0;return{a:i,open:h,x:h?i.fret-1+i.width/2:n.fret-.5,y:st(n.string)}},an=(n,i,h)=>{const s=n.slideTo??n.slideUnpitchTo??null,r=Math.min(1,Math.max(0,h/Math.max(n.sustain,.25)));return s===null||n.fret===0?i:i+(s-.5-i)*r*r*(3-2*r)},On=(n,i)=>(Zi(n,i)*Ht(n.string)+Qi(n,i))*_*cn,Bn=n=>{const i=f-n.time;return i<0||n.fret===0||!(Oe(n)>0)?0:On(n,Math.min(i,Math.max(n.sustain,.15)))},sn=new Map;for(const n of qt){const i=n.time-f,h=Math.max(n.sustain,.15);i>0||-i>h||n.fret===0||!(Oe(n)>0)||sn.set(n.string,{note:n,x:n.fret-.5,dy:Bn(n)})}const wn=(n,i=0,h=!1)=>{const s=sn.get(n),r=st(n)+i,g=h?[[0,r,0]]:[rn?[rn[n][0],rn[n][1]+i,0]:[-.6,r,0],[0,r,0]];if(!s)return A([...g,[$t+.6,r,0]],!1);A([...g,[s.x,r+s.dy,0],[$t+.6,r,0]],!1)},ln=n=>st(n.string)+Bn(n),Xt=Ui[o.headstock],Pe=($-j)/2,vn=o.stringOrder==="high"?-1:1,le=([n,i])=>[-n*Pe/mt,xt/2+i*Pe*vn,0],Wn=n=>(st(n)-xt/2)*vn/Pe,jt=Xt&&qi(Xt,Array.from({length:U},(n,i)=>Wn(i))),rn=jt?.ends.map(le),St=(n,i,h=1)=>{n&&(t.fillStyle=n,Y()),i&&(t.strokeStyle=i,t.lineWidth=h,N())},Ae=(n,i,h)=>{const[s,r]=le(n),[g,u]=v(s,r,0),[S]=v(s+i*Pe/mt,r,0),[,x]=v(s,r+h*Pe,0);t.beginPath(),t.ellipse(g,u,Math.abs(S-g),Math.abs(x-u),0,0,Math.PI*2)},Le=(n,i,h,s,r)=>A(li(`${n},${i},${h},${s},${r}`,()=>ai(n,i,h,s,r)).map(le)),Hn=()=>{for(const{u:h,side:s,edge:r}of jt.keys){const g=(u,S)=>[r+s*u,r+s*S];Xt.keys==="machine"?(Le(h-.15,h+.15,...g(-.12,.08),.03),St(I(o.text,.12),I(o.anchorLane,.35)),Le(h-.03,h+.03,...g(.06,.22),0),St(I(o.text,.28)),Le(h-.11,h+.11,...g(.2,.68),.1),St(I(o.text,.18),I(o.anchorLane,.55))):(Le(h-.035,h+.035,...g(-.05,.22),0),St(I(o.text,.28)),Ae([h,r+s*.18],.08,.04),St(I(o.text,.3)),Ae([h,r+s*.4],.14,.2),St(I(o.text,.18),I(o.anchorLane,.55)))}A(jt.outline.map(le));const[,n]=v(...le([0,1.6])),[,i]=v(...le([0,-1.2]));if(St(mi(t,n,i,o.floor0,o.ink)),t.save(),t.clip(),St(null,I(o.text,.07),.3*Pe*p),t.restore(),tt(!0,o.anchorLane,8),St(null,I(o.anchorLane,.6),Math.max(1.5,.03*p)),tt(!1),Xt.cover){A(li(Xt.cover,()=>ri(Xt.cover)).map(le)),St(I(o.text,.09),I(o.text,.4));for(const h of Xt.screws)Ae(h,.04,.04),St(I(o.nut,.85))}},Nn=n=>Vn*(.7+.14*(U-1-n)),Wi=()=>{if(e.plate?.key!==In||e.plate.t!==o)return e.plate={key:In,t:o},Hn();const n=e.plate;if(!n.image){const[i,h]=[[],[]];for(const J of[...jt.outline,...jt.keys.map(({u:F,side:z,edge:W})=>[F,W+z*.8])]){const[F,z]=v(...le(J));i.push(F),h.push(z)}const s=Math.floor(Math.max(0,Math.min(...i)-24)*d)/d,r=Math.min(m,Math.max(...i)+24),g=Math.floor(Math.max(0,Math.min(...h)-24)*d)/d,u=Math.min(Ot,Math.max(...h)+24);n.image=new OffscreenCanvas(Math.max(1,Math.ceil((r-s)*d)),Math.max(1,Math.ceil((u-g)*d)));const[S,x,k]=[t,_t,Qt];[t,_t,Qt,n.x,n.y]=[n.image.getContext("2d"),0,null,s,g],t.setTransform(d,0,0,d,-s*d,-g*d),t.lineCap=t.lineJoin="round",Hn(),[t,_t,Qt]=[S,x,k]}t.drawImage(n.image,n.x,n.y,n.image.width/d,n.image.height/d)},Fn=()=>{t.fillStyle=o.board,A([[0,j,0],[$t+.6,j,0],[$t+.6,$,0],[0,$,0]]),Y(),t.fillStyle=I(o.anchorFill,.16),A([[e.left,j,0],[e.right,j,0],[e.right,$,0],[e.left,$,0]]),Y(),t.fillStyle=o.inlayDot;const n=s=>(Math.max(0,Math.ceil(s)-1)+.5)*_;t.beginPath();for(const s of Cn)for(const r of s%12?[n((U-1)/2)]:[n((U-1)/4),xt-n((U-1)/4)]){const[g,u,S]=v(s-.5,r,0);t.moveTo(g+.1*S,u),t.ellipse(g,u,.1*S,.08*S,0,0,Math.PI*2)}Y(),R>0&&(t.fillStyle=I(o.ink,.5),A([[0,j,0],[R-Rn,j,0],[R-Rn,$,0],[0,$,0]]),Y()),jt&&Wi();const[,i]=v(vt[0],$,0),[,h]=v(vt[0],j,0);t.strokeStyle=mi(t,i,h,I(o.anchorPost,.75),o.post),t.lineWidth=Math.max(1.5,.05*p),t.beginPath();for(let s=1;s<=$t;s++)ut([s,j-.04,0],[s,$+.04,0]);N(),t.strokeStyle=o.nut,t.lineWidth=Math.max(3,.12*p),H([0,j-.06,0],[0,$+.06,0]),tt(!0,o.anchorPost,12),t.strokeStyle=o.anchorPost,t.lineWidth=Math.max(3,.07*p);for(const s of[e.left,e.right])H([s,j-.14,0],[s,$+.14,0]);tt(!1);for(let s=0;s<U;s++){const r=Nn(s);tt(!0,Ft(s),3),t.strokeStyle=I(Ft(s),.9),t.lineWidth=r,wn(s),N(),tt(!1),t.strokeStyle="rgba(255, 255, 255, 0.25)",t.lineWidth=Math.max(.6,r*.3),wn(s,.012),N()}if(jt&&(jt.ends.forEach(([s,r],g)=>{if(Xt.clamps)Le(s-.1,s+.1,r-.1,r+.1,.04),St(I(o.text,.22),I(o.text,.45)),Ae([s,r],.05,.05),St(o.nut);else{Ae([s,r],.17,.17),St(I(o.ink,.5),I(o.nut,.4)),Ae([s,r],.085,.085),St(o.nut),Ae([s,r],.03,.03),St(I(o.ink,.85));const[u,S,x]=v(...rn[g]),[k,J]=v(0,st(g),0),F=Math.atan2(J-S,k-u);t.beginPath(),t.arc(u,S,.1*Pe*x,F-1.3,F+1.3),St(null,Ft(g),Nn(g))}}),Xt.tree)){const s=[U-2,U-1].map(r=>{const[g,u]=jt.ends[r];return Wn(r)+(u-Wn(r))*Xt.tree/g});Le(Xt.tree-.05,Xt.tree+.05,Math.min(...s)-.08,Math.max(...s)+.08,.04),St(I(o.nut,.7),I(o.ink,.6))}for(const s of[!1,!0])for(let r=1;r<=$t;r++){const g=r>=Tt.fret&&r<Tt.fret+Tt.width,u=Cn.includes(r);(g||u)===s&&yt(String(r),r-.5,j-.3,0,g?.3:u?.26:.2,g?o.accent:u?o.inlay:o.numOff,s?800:500,"center",!1)}},Ge=(n,i)=>v(n,i,0).slice(0,2).map(h=>Math.round(h*d*10)).join(":"),In=[o.headstock,U,_,vn,m,d,Math.round(mt*1e4),Ge(0,j),Ge($t,j),Ge(0,$),Ge($t,$),Ge(-4,xt/2)].join(),hn=!sn.size&&[In,Tt.fret,Tt.width,R,Math.round(e.left*1e3),Math.round(e.right*1e3)].join();if(!hn||e.board?.key!==hn||e.board.t!==o)e.board=hn&&{key:hn,t:o},Fn();else{const n=e.board;if(!n.drawn){const i=[[0,$+.2],[$t,$+.2],[0,j-.9],[$t,j-.9]].map(([u,S])=>v(u,S,0)[1]);jt&&i.push(...[...jt.outline,...jt.keys.map(({u,side:S,edge:x})=>[u,x+S*.8])].map(u=>v(...le(u))[1]));const h=Math.floor(Math.max(0,Math.min(...i)-24)*d)/d,s=Math.min(Ot,Math.max(...i)+24),[r,g]=[Math.ceil(m*d),Math.max(1,Math.ceil((s-h)*d))];(e.boardImage?.width!==r||e.boardImage.height!==g)&&(e.boardImage=new OffscreenCanvas(r,g)),[t,_t,Qt,n.y,n.drawn]=[e.boardImage.getContext("2d"),h,null,h,!0],t.setTransform(1,0,0,1,0,0),t.clearRect(0,0,r,g),Ut(),t.lineCap=t.lineJoin="round",t.textBaseline="middle",Fn(),[t,_t,Qt]=[M,0,null]}t.drawImage(e.boardImage,0,n.y,e.boardImage.width/d,e.boardImage.height/d)}ue("board");const zn=(n,i)=>n.letRing&&-i>.25;for(const n of qt){const i=n.time-f;if(i>0||-i>Math.max(n.sustain,.15)||n.mute)continue;const h=Ft(n.string),s=ln(n);if(tt(!zn(n,i),h,10),t.strokeStyle=h,t.lineWidth=Vn+3,wn(n.string,0,!0),N(),tt(!1),-i<.2){const[r,g,u]=v(ge(n).x,s,0);t.save(),t.translate(r,g),t.scale(1,.4);const S=t.createRadialGradient(0,0,0,0,0,.5*u);S.addColorStop(0,I(o.flash,.8*(1+i/.2))),S.addColorStop(1,I(o.flash,0)),t.fillStyle=S,t.beginPath(),t.arc(0,0,.5*u,0,Math.PI*2),Y(),t.restore()}}t.strokeStyle=o.anchorLane,t.lineWidth=2.5,tt(!0,o.anchorLane,10);for(const n of l.handShapes??[]){if(n.startTime>f||n.endTime<=f||n.endTime-n.startTime<.3||!n.frets.some((s,r)=>s>=0&&r<U))continue;const[i,h]=rt(n.frets.filter((s,r)=>r<U),n.startTime);A([[i,j,0],[h,j,0],[h,$,0],[i,$,0]]),N()}if(tt(!1),R>0){const n=R-Rn;t.strokeStyle=o.nut,t.lineWidth=Math.max(4,.17*p),H([n,j-.16,0],[n,$+.16,0]),t.strokeStyle=I(o.ink,.45),t.lineWidth=Math.max(1,.05*p),H([n,j-.13,0],[n,$+.13,0])}ue("strings");for(const n of qt){const i=n.time-f,h=ct(i),s=me(n),{a:r,open:g,x:u,y:S}=ge(n),x=an(n,u,-i);if(i<-.15||Math.abs(v(x,S,h)[0]-m/2)>m/2+200)continue;const k=g?(r.width-.2)/2:.34;t.globalAlpha=i<0?Math.max(0,1+i/.15):Math.min(1,(E-i)/.4),!s&&Lt&&(t.strokeStyle=Lt,t.lineWidth=2,H([x-k,P,h],[x+k,P,h])),!(g||An(n))&&(t.strokeStyle=I(Ft(n.string),n.repeat||s?.highDensity?.35:.75),t.lineWidth=1.5,H([x,Math.min(S,ln(n))-.42*_,h],[x,P,h]))}t.globalAlpha=1;const Gn=(n,i,h)=>{const s=Array.from({length:13},(r,g)=>{const u=g/12;return[n[0]+(i[0]-n[0])*u,n[1]+(i[1]-n[1])*u+Math.sin(Math.PI*u)*h,n[2]+(i[2]-n[2])*u]});A(s,!1),N()};for(const n of eo(l)){if(n.end<=f||n.time>=f+E)continue;const[i,h]=rt(n.frets,n.time),s=n.time-f,r=ct(Math.max(s,0)),g=ct(Math.min(n.end-f,E));t.globalAlpha=Math.min(1,(E-Math.max(s,0))/.4),tt(!n.arpeggio,o.anchorLane,10,!0),t.strokeStyle=Wt(o.anchorLane,1,.2),t.lineWidth=3.5;for(const u of[i,h])H([u,P,r],[u,P,g]);tt(!1),n.arpeggio&&s>0&&(t.strokeStyle=I(o.anchorLane,.7),t.lineWidth=1.5,A([[i,P,r],[i,$,r],[h,$,r],[h,P,r]],!1),N(),n.arpeggio.name&&r>Re&&yt(n.arpeggio.name,i-.12,$/2,r,.34,o.text,600,"right"))}t.globalAlpha=1;const $n=(n,i)=>{const h=ge(n);return Math.abs(h.x-i)<(h.open?(h.a.width-.2)/2+.1:.45)};for(const[n,i]of qt.entries()){const h=i.time-f,s=me(i),r=i.slideTo??i.slideUnpitchTo??null,{a:g,open:u,x:S,y:x}=ge(i),k=Ft(i.string),J=ct(h),F=(u?(g.width-.2)/2:.34)*(i.grace?.6:1),z=(u?.12:.42)*_*(i.grace?.6:1);if(h>-.15&&!s?.highDensity&&!i.repeat){if(t.globalAlpha=Math.min(1,(E-h)/.4),t.strokeStyle=k,t.lineWidth=2,t.setLineDash([4,4]),i.slideIn&&H([S+(i.slideIn==="below"?-1.4:1.4),x-z,Math.max(0,J-1)],[S+(i.slideIn==="below"?-F:F),x,J]),i.slideOut&&H([S+(i.slideOut==="up"?F:-F),x,J],[S+(i.slideOut==="up"?1.4:-1.4),x-z,J+1]),t.setLineDash([]),typeof i.tieTo=="number"){const G=l.notes[i.tieTo],q=ge(G);t.setLineDash([5,4]),Gn([S,x+z,J],[q.x,q.y+z,ct(G.time-f)],_*.9),t.setLineDash([])}t.globalAlpha=1}const W=r===null?i.sustain:Math.max(i.sustain,.25),O=r!==null||i.bend||i.bendCurve||i.whammy;if(W<=.2||h+W<=0||s&&!O||An(i))continue;u&&r&&(t.strokeStyle=k,t.lineWidth=2.5,t.setLineDash(i.letRing?[7,6]:[]),Gn([S,x,ct(Math.max(h,0))],[r-.5,x,ct(Math.min(h+W,E))],_*1.5),t.setLineDash([]));let lt=null;for(let G=n+1;G<qt.length&&qt[G].time<=i.time+W+.02;G++){const q=qt[G];if(!(q.time<=i.time+.005)&&(me(q)||q.string===i.string||$n(q,S))){lt=q;break}}const nt=Math.max(h,0),X=i.bend||i.bendCurve||i.whammy;let at=Math.min(h+W,E,lt?lt.time-f:1/0);if(at<=nt)continue;const b=G=>{const q=G-h,it=ct(G),y=i.bend||i.bendCurve||i.whammy,T=i.vibrato&&!y?Math.sin(it/1.6*Math.PI*2)*_*(i.vibratoWide?.45:.25):0,C=i.tremolo?Math.floor(it/.3)%2?.05:-.05:0,Z=cn+(Bi-cn)*gi(Math.min(1,it/Hi));return[an(i,S,q)+C,x+T+On(i,q)*Z/cn,it]},kt=lt&&b(at)[0],It=lt&&me(lt)?.notes.find(G=>$n(l.notes[G],kt)),et=typeof It=="number"?l.notes[It]:lt;if(lt&&(X||$n(et,kt))){const G=ge(et),q=ct(et.time-f),it=G.open?(G.a.width-.2)/2:.34,y=v(G.x,G.y-(G.open?.12:.42)*_,q)[1]+3,[T]=v(G.x-it,G.y,q),[C]=v(G.x+it,G.y,q),Z=K=>{const[At,pe]=v(...b(K));return pe<y&&At>Math.min(T,C)-2&&At<Math.max(T,C)+2};if(Z(at)&&!Z(nt)){let K=nt,At=at;for(let pe=0;pe<24;pe++)[K,At]=Z((K+At)/2)?[K,(K+At)/2]:[(K+At)/2,At];at=K}if(at<=nt+.001)continue}const De=r===null&&!X&&!i.vibrato&&!i.tremolo?1:Math.min(400,Math.max(12,Math.ceil((at-nt)*dt*8))),Mt=Array.from({length:De+1},(G,q)=>b(nt+(at-nt)*q/De));if(u&&!s){t.fillStyle=Wt(k,i.letRing?.14:.26,.03),A([...Mt.map(([G,q,it])=>[G-F,q,it]),...Mt.slice().reverse().map(([G,q,it])=>[G+F,q,it])]),Y(),tt(!i.letRing,k,6,!0),t.strokeStyle=Wt(k,.95,.3),t.lineWidth=2.5,t.setLineDash(i.letRing?[7,6]:[]);for(const G of[-F,F])A(Mt.map(([q,it,y])=>[q+G,it,y]),!1),N();t.setLineDash([]),tt(!1)}else if(i.bend||i.bendCurve||i.whammy){const G=q=>A([...Mt.map(([it,y,T])=>[it-q,y,T]),...Mt.slice().reverse().map(([it,y,T])=>[it+q,y,T])]);G(dn),t.fillStyle=Wt(k,1,.6),Y(),G(dn*.35),t.fillStyle=Wt(_n(k,-.22),1,.55),Y(),tt(!0,k,8,!0),t.strokeStyle=Wt(_n(k,.6),1,.5),t.lineWidth=2;for(const q of[-dn,dn])A(Mt.map(([it,y,T])=>[it+q,y,T]),!1),N();tt(!1)}else tt(!i.letRing,k,6,!0),t.fillStyle=Wt(k,i.letRing?.4:.75,i.letRing?.15:.3),A([...Mt.map(([G,q,it])=>[G-.09,q,it]),...Mt.slice().reverse().map(([G,q,it])=>[G+.09,q,it])]),Y(),tt(!1);if((i.letRing||r!==null||!X&&(i.vibrato||i.tremolo))&&(t.strokeStyle=Wt(i.letRing?k:"#ffffff",.75,.3),t.lineWidth=i.letRing?2:1.5,t.setLineDash(i.letRing?[7,6]:[]),A(Mt,!1),N(),t.setLineDash([])),r!==null&&at>=Math.min(h+W,E)-.001){const[G,q,it]=b(h+W);t.strokeStyle=k,t.lineWidth=2,t.setLineDash(i.slideTo===null?[5,4]:[]),u?Pt(r-.5,q,it,.34,.42*_):Pt(G,q,it,F,z),N(),t.setLineDash([])}}ue("trails");const Un=new Set;for(let n=qt.length-1;n>=0;n--){const i=qt[n],h=i.time-f,s=ct(h),r=me(i),{a:g,open:u,x:S}=ge(i),x=an(i,S,-h),k=ln(i),J=i.mute||r?.fretHandMute,F=i.palmMute||r?.palmMute,z=Ft(i.string),W=(u?(g.width-.2)/2:.34)*(i.grace?.6:1),O=(u?.12:.42)*_*(i.grace?.6:1),lt=i.slideTo??i.slideUnpitchTo??null;if(h<-.15)continue;const nt=h<0?Math.max(0,1+h/.15):Math.min(1,(E-h)/.4);if(t.globalAlpha=nt,r&&!Un.has(i.chord)){Un.add(i.chord);const[y,T]=rt(r.notes.map(ht=>l.notes[ht].fret),i.time),C=t.globalAlpha,Z=s<Re,K=Z?.65:r.highDensity&&o.repeatMarks!=="frame"?.18:.5;if(A([[y,P,s],[T,P,s],[T,$,s],[y,$,s]]),o.frames==="gradient"){const[,ht]=v(y,P,s),[,Et]=v(y,$,s),Dt=Z?o.anchorLane:o.anchorFill;ze(di(t,`${Dt}|${K}`,[[0,I(Dt,K*.6)],[1,I(Dt,0)]]),ht,Et)}else t.globalAlpha=C*K,r.highDensity||(t.fillStyle=o.chordFill,Y()),t.strokeStyle=Z?o.anchorLane:o.chordBox,t.lineWidth=Z||!r.highDensity?1.5:1.2,tt(Z,o.anchorLane,8),N(),tt(!1);if(t.globalAlpha=C,t.strokeStyle=Lt,t.lineWidth=2,Lt&&H([y,P,s],[T,P,s]),r.highDensity&&(r.palmMute||r.fretHandMute)&&(t.strokeStyle=r.palmMute?o.muted:"#ffffff",fe((y+T)/2,P+_*.4,s,r.palmMute?.22:.12,_*(r.palmMute?.35:.22))),r.accent){const ht=Math.min(.6,(T-y)*.22),Et=($-P)*.35,Dt=Math.min(1,v(y,$,s)[2]/v(y,$,Re)[2]);t.strokeStyle="#ffffff",t.lineWidth=Math.max(1,3.5*Dt*(r.accent==="heavy"?1.4:1)),t.lineCap="square",tt(!0,"#ffffff",Math.max(2,12*Dt)),A([[y,$-Et,s],[y,$,s],[y+ht,$,s]],!1),N(),A([[T-ht,$,s],[T,$,s],[T,$-Et,s]],!1),N(),tt(!1),t.lineCap="round"}if(r.barre&&(!r.highDensity||o.repeatMarks==="grey")){const ht=r.barre.fret-.5;t.strokeStyle=r.highDensity?o.muted:"rgba(255, 255, 255, 0.7)",t.lineWidth=Math.max(3,.1*v(ht,xt/2,s)[2]);const[Et,Dt]=[st(r.barre.from),st(r.barre.to)].sort((re,Kt)=>re-Kt);H([ht,Et-_*.4,s],[ht,Dt+_*.4,s]),yt(r.barre.half?"½B":"B",ht,$+.12,s,.22,r.highDensity?o.muted:o.text)}if(r.strum||r.roll){const ht=y-.25,Et=st(0)>st(U-1)?$-.1:P+.15,Dt=Et>xt/2?P+.15:$-.1,[re,Kt]=(r.strum??r.roll)==="down"?[Et,Dt]:[Dt,Et];t.strokeStyle=o.text,t.lineWidth=2,r.roll?A(Array.from({length:17},(so,Kn)=>[ht+Math.sin(Kn/16*Math.PI*6)*.06,re+(Kt-re)*Kn/16,s]),!1):A([[ht,re,s],[ht,Kt,s]],!1),N();const Ce=Kt<re?.14:-.14;H([ht-.08,Kt+Ce,s],[ht,Kt,s]),H([ht+.08,Kt+Ce,s],[ht,Kt,s])}const At=l.chords[i.chord-1],pe=!At||i.time-At.time>1||At.name!==r.name;s>Re&&r.name&&!r.highDensity&&pe&&yt(r.name,y-.12,$/2,s,.34,o.text,600,"right")}const[X,at,b]=v(x,k,s);if(X<-200||X>m+200||An(i)){t.globalAlpha=1;continue}const kt=i.repeat||r?.highDensity;if(kt){const y=s<Re;t.globalAlpha*=y?.9:.4,t.strokeStyle=z,t.lineWidth=y?2:1.5,tt(y,z,8),Pt(x,k,s,W,O),N(),tt(!1),(J||F)&&o.repeatMarks!=="hide"&&Ie(x,k,s,b,u?.34:W,u?_*.3:O,F,o.muted),t.globalAlpha=nt}else{if(!u&&he){const y=i.harmonic||i.harmonicPinch?`<${i.fret}>`:i.ghost?`(${i.fret})`:String(i.fret),T=i.grace?.7:1;ee(y,x,Math.max(.35,s-.55),ti*T,ei*T,I(z,he))}if(i.dynamicLabel&&yt(i.dynamicLabel,x-.6,P,s,.3,o.text,"italic 700","right"),i.ghost&&(t.globalAlpha=nt*.5),o.gem==="pill")o.notes3d!==!1&&(Pt(x,k,s+Zn,W,O),t.fillStyle=z,Y(),t.fillStyle="rgba(255, 255, 255, 0.35)",Y()),Pt(x,k,s,W,O),t.fillStyle=z,Y();else{const y=i.harmonic||i.harmonicPinch,T=Zn;if(!y&&o.notes3d!==!1)for(const[K,At]of[[[[x-W,k+O,s],[x+W,k+O,s],[x+W,k+O,s+T],[x-W,k+O,s+T]],"rgba(255, 255, 255, 0.35)"],[[[x-W,k-O,s],[x-W,k+O,s],[x-W,k+O,s+T],[x-W,k-O,s+T]],"rgba(0, 0, 0, 0.4)"],[[[x+W,k-O,s],[x+W,k+O,s],[x+W,k+O,s+T],[x+W,k-O,s+T]],"rgba(0, 0, 0, 0.4)"]])A(K),t.fillStyle=z,Y(),t.fillStyle=At,Y();tt(s<Re,z,8),t.fillStyle=z,y?A([[x,k+O*1.3,s],[x+W*.8,k,s],[x,k-O*1.3,s],[x-W*.8,k,s]]):Pt(x,k,s,W,O),Y(),tt(!1);const[,C]=v(x,k+O,s),[,Z]=v(x,k-O,s);ze(di(t,"shine",[[0,"rgba(255, 255, 255, 0.45)"],[.5,"rgba(255, 255, 255, 0)"],[1,"rgba(0, 0, 0, 0.25)"]]),C,Z),t.strokeStyle="rgba(255, 255, 255, 0.6)",t.lineWidth=1,N()}if((J||F)&&Ie(x,k,s,b,u?.34:W,u?_*.3:O,F,u&&F?z:null),!u&&!J&&!F){const y=i.finger??(r?.fingers?.[i.string]>=0?r.fingers[i.string]:null),T=y!==null?y===0?"T":String(y):"";if(T){const C=t.globalAlpha;t.globalAlpha=C*Math.min(1,Math.max(0,(1-h/E)/.4)),yt(T,x,k,s-.01,_*.62,Zt,700,"center",We,!0),t.globalAlpha=C}}}if(kt&&o.repeatMarks==="hide"){t.globalAlpha=1;continue}const It=kt?o.muted:o.text;if(t.globalAlpha=nt*(kt?.8:1)*Math.min(1,Math.max(0,(1-h/E)/.15)),i.ghost){const[y]=v(x-W,k,s),[T]=v(x+W,k,s),C=O*b*1.5;t.strokeStyle=kt?It:z,t.lineWidth=Math.max(1.2,.035*b),t.beginPath(),t.arc(y+C*.35,at,C,Math.PI*.7,Math.PI*1.3),N(),t.beginPath(),t.arc(T-C*.35,at,C,-Math.PI*.3,Math.PI*.3),N()}if(i.grace&&(t.strokeStyle=It,t.lineWidth=Math.max(1,.03*b),Xe(t,X-W*b*mt*1.2,at+O*b*1.4,X+W*b*mt*1.2,at-O*b*1.4)),i.showString){const[y]=v(x-W,k,s),T=.12*b,C=y-T-.06*b;t.strokeStyle=t.fillStyle=kt?It:z,t.lineWidth=Math.max(1,.025*b),t.beginPath(),t.arc(C,at,T,0,Math.PI*2),N(),oe(String(U-i.string),C,at,.15*b,700,"center"),t.fillText(String(U-i.string),0,0),Ut()}let et=at-O*b-.18*b;t.strokeStyle=t.fillStyle=It,t.lineWidth=Math.max(1.2,.04*b),t.textAlign="center";const Dn=(y,T,C)=>{t.beginPath();for(let Z=0;Z<=20;Z++)t[Z?"lineTo":"moveTo"](X-y+2*y*Z/20,et+Math.sin(Z/20*Math.PI*2*C)*T);N()},De=(y,T,C="700")=>{T*b<2||(oe(y,X,et,T*b,C,"center"),t.fillText(y,0,0),Ut(),et-=(T+.04)*b)};let Mt=at-O*b;const G=i.tap&&!i.tapLeft;if((i.hammerOn||i.pullOff)&&!G){const y=i.grace?.6:1,T=.2*b*mt*y,C=.38*_*b*y,[Z,K]=i.hammerOn?[Mt+.4*C,Mt-.6*C]:[Mt-.6*C,Mt+.4*C];t.beginPath(),t.moveTo(X-T,K),t.lineTo(X+T,K),t.lineTo(X,Z),t.closePath(),t.fillStyle=kt?It:"#ffffff",t.strokeStyle=I(o.ink,.9),t.lineWidth=Math.max(1.5,.03*b),N(),Y(),Mt-=.6*C,et=Math.min(et,Mt-.14*b),t.strokeStyle=t.fillStyle=It,t.lineWidth=Math.max(1.2,.04*b)}if(G){const y=i.grace?.6:1,T=.28*b*mt*y,C=.62*_*b*y,Z=Mt+.15*C,K=Z-C;t.beginPath(),t.moveTo(X,Z),t.lineTo(X+T,K),t.lineTo(X,K+.38*C),t.lineTo(X-T,K),t.closePath(),t.strokeStyle=I(o.ink,.9),t.lineWidth=Math.max(3.5,.1*b),N(),t.fillStyle=kt?I(It,.4):I(_n(z,.55),.85),Y(),t.strokeStyle=kt?It:z,t.lineWidth=Math.max(1.8,.05*b),N(),Mt=K,et=Math.min(et,Mt-.14*b),t.strokeStyle=t.fillStyle=It,t.lineWidth=Math.max(1.2,.04*b)}const q=Oe(i);if(q>0){const y=i.bendCurve?.[0]?.[1]>0,T=(i.bendCurve?.length??0)>1&&i.bendCurve.at(-1)[1]<q,C=Math.min(3,Math.max(1,Math.round(q*2))),Z=W*b*mt*.6,K=W*b*.3,At=K*1.25,pe=I(o.ink,.9);let ht=Mt-.04*b;const Et=Kt=>{for(let Ce=0;Ce<C;Ce++)Pi(t,X,ht-Ce*At-(Kt>0?0:K),Z,K,Kt,kt?It:z,pe);ht-=C*At+.08*b},Dt=Ht(i.string);(!y||!T)&&Et(-Dt),T&&Et(Dt);const re=`${y?"pre ":""}${yi(q)}`;t.fillStyle=It,oe(re,X+Z+.08*b,(at-O*b+ht)/2,.22*b,700,"left"),t.fillText(re,0,0),Ut(),t.textAlign="center",et=Math.min(et,ht-.1*b)}i.staccato&&(t.beginPath(),t.arc(X,et+.04*b,Math.max(1.5,.045*b),0,Math.PI*2),Y(),et-=.16*b),i.accent&&(i.accent==="tenuto"||!r?.accent)&&De({heavy:"^",tenuto:"–"}[i.accent]??">",.3);const it=[i.tapLeft?"m.g.":"",bi[i.harmonicType]??(i.harmonicPinch?"PH":""),i.slap?"slap":i.pop?"pop":"",i.golpe?`golpe (${i.golpe})`:"",i.rasgueado?`rasg. ${i.rasgueado}`:"",typeof i.trill=="number"?`tr ${i.trill}`:"",i.ornament??"",i.fade??"",i.whammy?"w/bar":"",i.wah==="open"?"o":i.wah==="closed"?"+":""];for(const y of it)y&&De(y,y.length>2?.22:.28);if(i.rightFinger&&De(i.rightFinger,.26,"italic 700"),i.vibrato&&(Dn(.24*b,(i.vibratoWide?.07:.035)*b,2),et-=(.16+(i.vibratoWide?.06:0))*b),i.pick){const y=.09*b,T=.13*b;t.beginPath(),i.pick==="down"?[[-y,T/2],[-y,-T/2],[y,-T/2],[y,T/2]].forEach(([C,Z],K)=>t[K?"lineTo":"moveTo"](X+C,et+Z)):[[-y,-T/2],[0,T/2],[y,-T/2]].forEach(([C,Z],K)=>t[K?"lineTo":"moveTo"](X+C,et+Z)),N(),et-=.22*b}if(i.fermata&&(t.beginPath(),t.arc(X,et+.06*b,.14*b,Math.PI,0),N(),t.beginPath(),t.arc(X,et+.02*b,Math.max(1.5,.03*b),0,Math.PI*2),Y(),et-=.24*b),i.tremolo){for(let y=-1;y<=1;y++)Xe(t,X-.12*b,et+(y*.08+.05)*b,X+.12*b,et+(y*.08-.05)*b);et-=.3*b,Dn(.14*b,.04*b,1.5),et-=.14*b}if(lt!==null&&!u){const y=Math.sign(lt-i.fret)||1,T=X-y*.16*b,C=X+y*.16*b,Z=et+.07*b,K=et-.09*b;Xe(t,T,Z,C,K),Xe(t,C,K,C-y*.1*b,K),Xe(t,C,K,C,K+.1*b),et-=.3*b}t.globalAlpha=1}ue("notes");const Yn=new Set;for(const n of qt){const i=n.time-f,h=me(n);if(!h?.barre||Yn.has(h)||i>.06||i<-Math.max(n.sustain,.12))continue;Yn.add(h),t.strokeStyle="rgba(255, 255, 255, 0.85)",t.lineWidth=Math.max(4,.12*p);const[s,r]=[st(h.barre.from),st(h.barre.to)].sort((g,u)=>g-u);H([h.barre.fret-.5,s-_*.45,0],[h.barre.fret-.5,r+_*.45,0])}const qn=new Set,Xn=new Set;for(const n of qt){const i=n.time-f,h=me(n),s=sn.get(n.string),r=n.heldFrom??null,g=i<=.06||r!==null&&f>=r-.06,u=(n.slideTo??n.slideUnpitchTo??null)!==null;if(n.mute||i>fn||i<-Math.max(n.sustain,u?.25:.12)||(h?.highDensity||r!==null)&&!g||s&&s.note!==n&&!g||g&&qn.has(`${n.string}:${n.fret}`))continue;g&&qn.add(`${n.string}:${n.fret}`),Xn.add(`${n.string}:${n.fret}`);const{a:S,open:x,x:k}=ge(n),J=an(n,k,-i),F=ln(n),z=Ft(n.string),W=(x?(S.width-.2)/2:.32)+2/p,O=(x?.1:.36)*_+2/p;if(Pt(J,F,0,W,O),g)tt(!zn(n,i),z,14),t.fillStyle=z,Y(),tt(!1),t.strokeStyle="rgba(255, 255, 255, 0.7)",t.lineWidth=1.5,N();else{const nt=(1-i/fn)**2;t.globalAlpha=.35*nt,t.fillStyle=z,Y(),t.globalAlpha=.25+.75*nt,t.strokeStyle=z,t.lineWidth=2.2,N()}const lt=n.finger??(h?.fingers?.[n.string]>=0?h.fingers[n.string]:null);if(!x&&lt!==null&&yt(lt===0?"T":String(lt),J,F,0,_*.55,g?Zt:o.text,800,"center",!g||We),!x&&Oe(n)>0){const nt=Ht(n.string),X=n.bendCurve?.[0]?.[1]>0&&n.bendCurve.at(-1)[1]<Oe(n),[at,b]=v(J,F+nt*O,0);Pi(t,at,b-nt*(X?.14:.05)*p,.17*p*mt,.085*p,(X?1:-1)*nt,"#ffffff",I(o.ink,.9))}t.globalAlpha=1}for(const n of l.handShapes??[])!n.arpeggio||n.startTime-f>fn||n.endTime<=f||(t.globalAlpha=.3+.5*Math.min(1,1-(n.startTime-f)/fn)**2,n.frets.forEach((i,h)=>{if(i<=0||h>=U||Xn.has(`${h}:${i}`))return;const s=i-.5,r=st(h),g=n.fingers[h];Pt(s,r,0,.32+2/p,.36*_+2/p),t.strokeStyle=Ft(h),t.lineWidth=2.2,N(),g>=0&&yt(g===0?"T":String(g),s,r,0,_*.55,o.text,800)}),t.globalAlpha=1);ue("targets");const jn=to(l),Ln=jn.findLast(n=>n.time<=f&&f<n.end+.3),Ii=Ln?null:jn.find(n=>n.time>f&&n.time-f<1.2),Ue=Ln??Ii;if(Ue){const[n,i]=v(e.right+.4,$+.5,0),h=Jt(t,ce[700]??=`700 ${Bt}px ${o.num}`,Ue.name).width*52/Bt;t.globalAlpha=Ln?1:Math.max(.35,1-(Ue.time-f)/1.2),t.fillStyle=o.text,oe(Ue.name,Math.min(n,m-24-h),i,52,700,"left"),t.fillText(Ue.name,0,0),Ut(),t.globalAlpha=1}ue("labels")}const io=240,oo=64,xe=100,Be=24,wi=150;function ao(a,l){if(a.tabPages?.length===l)return a.tabPages.pages;const f=a.notes.at(-1),o=Math.max(f?f.time+f.sustain:0,a.beats.at(-1)?.time??0)+.5;let e=a.beats.filter(d=>d.measure>=0).map(d=>d.time);e.length<2&&(e=Array.from({length:Math.ceil(o/l)+1},(d,t)=>t*l)),e=[Math.min(0,e[0]),...e.filter(d=>d>0),Math.max(o,e.at(-1)+.01)];const M=[];let m=e[0];for(let d=1;d<e.length;d++)e[d]-m>l&&e[d-1]>m&&M.push({start:m,end:m=e[d-1]});M.push({start:m,end:e.at(-1)});for(let d=0;d<M.length-1;d++)M[d].end=M[d+1].start;return a.tabPages={length:l,pages:M},M}function fo(a,l,f,o){const{g:e,W:M}=Ai(a);if(!l)return;const m=l.strings,d=Math.min(oo,320/Math.max(1,m-1))*(o.boardHeight??1),t=Ot*.62-d*(m-1)/2,L=t+d*(m-1),R=t-d*1.65,Tt=L+d*1.45,U=w=>t+(o.stringOrder==="high"?m-1-w:w)*d,wt=io*(o.noteSpeed??1),_=o.tabLayout==="pages",xt=xe+30,st=M-Be-30,Ht=_?Math.min(170,(st-xt)*.14):0,dt=st-(_?Ht+24:0);let E,j,$,P,Nt=null;if(_){const w=ao(l,(dt-xt)/wt),Q=Math.max(0,w.findLastIndex(Ct=>Ct.start<=f)),V=w[Q],bt=(dt-xt)/(V.end-V.start);E=Ct=>xt+(Ct-V.start)*bt,[$,P]=[V.start,V.end-.001],j=E(Math.min(Math.max(f,V.start),V.end)),w[Q+1]&&(Nt={start:w[Q+1].start,scale:bt})}else j=Math.max(xe+wi+60,M*.2),E=w=>j+(w-f)*wt,[$,P]=[f-(j-xe)/wt,f+(M-j)/wt];const ct=w=>o.str[w%o.str.length],Ft=w=>w.chord===null||w.chord===void 0?null:l.chords[w.chord],Lt=(w,Q,V,bt)=>{e.beginPath(),e.moveTo(w,Q),e.lineTo(V,bt),e.stroke()},he=(w,Q,V,bt)=>{const Ct=Math.hypot(V,bt),[te,zt]=[V/Ct,bt/Ct];Lt(w,Q,w-6*te-4*zt,Q-6*zt+4*te),Lt(w,Q,w-6*te+4*zt,Q-6*zt-4*te)},Vt=w=>w>=j-1?1:.4;e.lineCap="round",e.lineJoin="round",e.textBaseline="alphabetic";const vt=[],we=w=>{w&&(e.save(),e.beginPath(),e.rect(w[0],0,w[1]-w[0],Ot),e.clip());const Q=`600 ${Me(Math.min(15,d*.26))}px ${o.num}`,V=`700 ${Me(Math.min(13,d*.22))}px ${o.num}`,bt=new Map;e.font=Q,e.textAlign="left";const Ct=new Path2D,te=new Path2D;e.fillStyle=o.muted;for(let p=_e(l.beats,$-1);p<l.beats.length;p++){const c=l.beats[p];if(c.time>P)break;const D=E(c.time),gt=c.measure>=0,A=gt?Ct:te;A.moveTo(D,t-d*.35),A.lineTo(D,L+d*.35),gt&&(e.fillText(String(c.measure),D+6,R+d*.36),bt.set(Math.round(c.time*50),Jt(e,Q,String(c.measure)).width+16))}e.lineWidth=1,e.strokeStyle=I(o.text,.05),e.stroke(te),e.lineWidth=1.5,e.strokeStyle=I(o.text,.16),e.stroke(Ct),e.fillStyle=o.accent;const zt=new Map;for(const p of l.markers??[])p.time>=$&&p.time<=P&&zt.set(Math.round(p.time*50),[...zt.get(Math.round(p.time*50))??[],p.text]);for(const[p,c]of zt)e.fillText([...new Set(c)].join(" · "),E(p/50)+6+(bt.get(p)??0),R+d*.36);e.strokeStyle=I(o.text,.14),e.beginPath();for(let p=0;p<m;p++)e.moveTo(xe,U(p)),e.lineTo(M-Be,U(p));e.stroke();const ve=L+d*.92,Rt=L+d*1.24;if(o.guides!==!1){e.font=Q,e.fillStyle=e.strokeStyle=o.anchorLane,e.lineWidth=2;let p=-1/0;const c=l.anchors??[];for(let D=Math.max(1,_e(c,$));D<c.length&&c[D].time<=P;D++){const gt=c[D],A=E(gt.time);if(A<p)continue;const H=`fret ${gt.fret}`;e.globalAlpha=Vt(A),Lt(A,L+d*.6,A,ve-2),e.fillText(H,A+5,ve),p=A+5+Jt(e,Q,H).width+8}e.globalAlpha=1}e.strokeStyle=o.text,e.lineWidth=1.5;for(const p of l.hairpins??[]){if(p.endTime<$||p.time>P)continue;const c=E(p.time),D=Math.max(c+30,E(p.endTime)),[gt,A]=p.kind==="cresc"?[c,D]:[D,c];e.globalAlpha=Vt(D),e.beginPath(),e.moveTo(A,Rt-11),e.lineTo(gt,Rt-5),e.lineTo(A,Rt+1),e.stroke()}e.globalAlpha=1;const be=Me(Math.min(26,d*.42)),Gt=be*1.3,Ke=be*.32,Je=o.gem==="pill"?Gt/2:5,mt={note:`700 ${be}px ${o.num}`,grace:`700 ${Me(be*.72)}px ${o.num}`,finger:`700 ${Me(be*.5)}px ${o.num}`},Ve=o.markings==="white";for(const p of l.handShapes??[]){if(!p.arpeggio||p.endTime<$||p.startTime>P)continue;const c=p.frets.flatMap((A,H)=>A>=0&&H<m?[U(H)]:[]);if(!c.length)continue;const D=E(p.startTime)-12,gt=E(p.endTime);e.globalAlpha=Vt(gt),e.strokeStyle=I(o.text,.4),e.lineWidth=1.5,e.setLineDash([6,5]),e.beginPath(),e.roundRect(D,Math.min(...c)-Gt/2-6,gt-D,Math.max(...c)-Math.min(...c)+Gt+12,8),e.stroke(),e.setLineDash([]),p.name&&(e.font=`700 ${Me(Math.min(24,d*.4))}px ${o.num}`,e.fillStyle=o.text,e.fillText(p.name,D,t-d*.72))}e.globalAlpha=1;const Ne=p=>(p.slideTo??p.slideUnpitchTo??null)!==null||!!p.slideOut,bn=p=>{const c=Ft(p);return!!c&&!p.repeat&&!c.highDensity&&c.notes.length>1},yn=(p,c)=>4+(Ne(p)?16:0)+(bn(c)?10:0)+(c.slideIn?18:0)+(c.showString?20:0);let Ze=0,Fe=0;const ye=(p,c)=>{c(Fe-p/2),Fe-=p+3},Sn={"":V,"italic ":`italic ${V}`},Se=(p,c="")=>ye(10,D=>{e.font=Sn[c],e.fillText(p,Ze,D+5)}),{next:kn,prev:Qe,held:Tn}=hi(l),tn=new Map,en=new Set,v=[],nn=[];for(let p=_e(l.notes,$-Tn-.5);p<l.notes.length;p++){const c=l.notes[p];if(c.time>P)break;if(E(c.time+c.sustain)<xe-40-Gt*4||w&&c.time<$&&E(c.time+c.sustain)-2<=E($)&&typeof c.tieTo!="number")continue;const D=Ft(c),gt=c.grace?.72:1,A=Gt*gt,H=U(c.string),Pt=ct(c.string),rt=E(c.time),fe=c.mute||D?.fretHandMute,We=c.palmMute||D?.palmMute,Zt=c.repeat||D?.highDensity,Ie=fe?"×":c.harmonic||c.harmonicPinch?`<${c.fret}>`:c.ghost?`(${c.fret})`:String(c.fret),Qt=c.finger??(D?.fingers?.[c.string]>=0?D.fingers[c.string]:null),_t=fe||c.fret===0||Qt===null?"":Qt===0?"T":String(Qt),ke=c.grace?mt.grace:mt.note,ce=Jt(e,ke,Ie).width,oe=_t?Jt(e,mt.finger,_t).width+3:0,Ut=l.notes[kn[p]],ze=Ut?E(Ut.time)-yn(c,Ut):1/0,yt=Math.min(Math.max(A,ce+oe+Ke*2*gt),Math.max(10,ze-rt)),ee=Math.max(rt+yt,Math.min(E(c.time+c.sustain)-2,ze)),pt=rt+yt/2,$e=Math.min(1,(yt-4)/(ce+oe)),Wt=tn.get(c.string)??(Qe[p]>=0?{x0:E(l.notes[Qe[p]].time),w:Gt}:null);if(tn.set(c.string,{x0:rt,w:yt}),ee<xe-40&&typeof c.tieTo!="number")continue;const Yt=c.time<=f&&f<c.time+Math.max(c.sustain,.15),tt=(Yt||rt>=j-1?1:.4)*(c.ghost?.55:1);if(e.globalAlpha=tt,D&&!en.has(D)){en.add(D);const de=D.notes.map(B=>U(l.notes[B].string)),ae=Math.min(...de)-Gt/2,N=Math.max(...de)+Gt/2,Y=rt-7;if(de.length>1&&!Zt&&(e.strokeStyle=D.accent?"#ffffff":I(o.text,.7),e.lineWidth=D.accent==="heavy"?4:D.accent?3:2,e.beginPath(),e.moveTo(Y+4,ae),e.lineTo(Y,ae),e.lineTo(Y,N),e.lineTo(Y+4,N),e.stroke()),e.font=V,e.fillStyle=e.strokeStyle=Zt?o.muted:o.text,e.lineWidth=1.8,e.textAlign="left",D.barre&&!Zt&&e.fillText(`${D.barre.half?"½":""}B${D.barre.fret}`,Y,ae-5),D.strum||D.roll){const B=D.notes.map(ie=>l.notes[ie].string),ot=U(Math.min(...B)),ft=U(Math.max(...B)),[ut,ne]=(D.strum??D.roll)==="down"?[ot,ft]:[ft,ot],Te=Y-9;e.beginPath();for(let ie=0;ie<=16;ie++)e.lineTo(Te+(D.roll?Math.sin(ie/16*Math.PI*6)*2.5:0),ut+(ne-ut)*ie/16);e.stroke(),he(Te,ne,0,ne-ut||1)}const se=l.chords[c.chord-1];D.name&&!Zt&&(!se||c.time-se.time>1||se.name!==D.name)&&(e.font=`700 ${Me(Math.min(24,d*.4))}px ${o.num}`,e.fillStyle=o.text,e.fillText(D.name,rt,t-d*.72))}e.beginPath(),e.roundRect(rt,H-A/2,ee-rt,A,Je*gt),Yt&&!Zt&&(e.shadowColor=Pt,e.shadowBlur=18),Zt?(e.strokeStyle=Pt,e.lineWidth=2,e.stroke()):c.letRing&&ee>rt+yt+2?(e.fillStyle=I(Pt,.3),e.fill(),e.shadowBlur=0,e.strokeStyle=Pt,e.lineWidth=2,e.setLineDash([6,5]),Lt(rt+yt+4,H,ee-4,H),e.setLineDash([]),e.beginPath(),e.roundRect(rt,H-A/2,yt,A,Je*gt),e.fillStyle=Pt,e.fill()):(e.fillStyle=fe?I(o.text,.22):Pt,e.fill()),e.shadowBlur=0,Yt&&vt.push({y:H,c:Pt});const Pn=Zt?Pt:fe?o.text:Ve?"#ffffff":o.ink;v.push({text:Ie,font:ke,finger:_t,fill:Pn,shown:tt,squeeze:$e,x:pt,y:H+Jt(e,ke,Ie).middle,left:-(ce+oe)/2,textWidth:ce}),nn.push(()=>{e.globalAlpha=tt;const de=Zt?o.muted:o.text;e.strokeStyle=e.fillStyle=de,e.lineWidth=1.6;const ae=c.slideTo??c.slideUnpitchTo??null,N=ae===null?c.slideOut==="up"?1:c.slideOut?-1:0:Math.sign(ae-c.fret)||1;if(N){const B=c.slideTo===null&&c.slideUnpitchTo!==null&&c.slideUnpitchTo!==void 0;B&&e.setLineDash([3,3]),Lt(ee+4,H+N*A*.3,ee+14,H-N*A*.3),B&&e.setLineDash([])}if(c.slideIn&&Lt(rt-16,H+(c.slideIn==="below"?1:-1)*A*.3,rt-6,H-(c.slideIn==="below"?1:-1)*A*.3),typeof c.tieTo=="number"){const B=E(l.notes[c.tieTo].time)+A/2;e.setLineDash([4,3]),e.beginPath(),e.moveTo(pt,H+A/2+3),e.quadraticCurveTo((pt+B)/2,H+A/2+14,B,H+A/2+3),e.stroke(),e.setLineDash([])}if(c.showString){const B=rt-(D?26:13);e.beginPath(),e.arc(B,H,8,0,Math.PI*2),e.stroke(),e.font=mt.finger,e.textAlign="center",e.fillText(String(m-c.string),B,H+Jt(e,mt.finger,"1").middle)}c.dynamicLabel&&(e.font=`italic ${V}`,e.textAlign="left",e.fillStyle=o.text,e.fillText(c.dynamicLabel,rt,Rt),e.fillStyle=de);let Y=H-A/2-6;if(c.vibrato){e.beginPath();for(let B=rt+2;B<=Math.max(ee,rt+24)-2;B+=2)e.lineTo(B,Y+Math.sin((B-rt)/3)*(c.vibratoWide?3:1.8));e.stroke(),Y-=c.vibratoWide?10:8}if(e.textAlign="center",e.font=V,(c.hammerOn||c.pullOff)&&Wt){const B=Wt.x0+Wt.w/2,ot=(B+pt)/2;e.beginPath(),e.moveTo(B,Y),e.quadraticCurveTo(ot,Y-12,pt,Y),e.stroke(),e.fillText(c.hammerOn?"H":"P",ot,Y-9),Y-=10}const se=Oe(c);if(se>0){const B=c.bendCurve?.[0]?.[1]>0,ot=(c.bendCurve?.length??0)>1&&c.bendCurve.at(-1)[1]<se,ft=rt+yt-2,ut=H-A/2,ne=ut-16;e.beginPath(),B?(e.moveTo(ft,ut),e.lineTo(ft,ne)):(e.moveTo(ft-4,ut+2),e.quadraticCurveTo(ft+4,ut,ft+6,ne)),e.stroke(),he(B?ft:ft+6,ne,B?0:.3,-1),ot&&(e.beginPath(),e.moveTo(ft+12,ne),e.quadraticCurveTo(ft+16,ut-6,ft+16,ut),e.stroke(),he(ft+16,ut,0,1)),e.textAlign="left",e.fillText(`${B?"pre ":""}${yi(se)}`,ft+(ot?20:10),ne+4),e.textAlign="center"}[Ze,Fe]=[pt,Y],c.tap&&!c.tapLeft&&Se("T"),c.staccato&&ye(4,B=>{e.beginPath(),e.arc(pt,B,2,0,Math.PI*2),e.fill()}),c.accent&&(c.accent==="tenuto"||!D?.accent)&&Se({heavy:"^",tenuto:"–"}[c.accent]??">"),We&&Se("PM");for(const B of[c.tapLeft?"m.g.":"",bi[c.harmonicType]??(c.harmonicPinch?"PH":""),c.slap?"slap":c.pop?"pop":"",c.golpe?`golpe (${c.golpe})`:"",c.rasgueado?`rasg. ${c.rasgueado}`:"",typeof c.trill=="number"?`tr ${c.trill}`:"",c.ornament??"",c.fade??"",c.whammy?"w/bar":"",c.wah==="open"?"o":c.wah==="closed"?"+":""])B&&Se(B);c.rightFinger&&Se(c.rightFinger,"italic "),c.pick&&ye(9,B=>{e.beginPath(),c.pick==="down"?[[-4,4.5],[-4,-4.5],[4,-4.5],[4,4.5]].forEach(([ot,ft],ut)=>e[ut?"lineTo":"moveTo"](pt+ot,B+ft)):[[-4,-4.5],[0,4.5],[4,-4.5]].forEach(([ot,ft],ut)=>e[ut?"lineTo":"moveTo"](pt+ot,B+ft)),e.stroke()}),c.fermata&&ye(9,B=>{e.beginPath(),e.arc(pt,B+4,7,Math.PI,0),e.stroke(),e.beginPath(),e.arc(pt,B+3,1.5,0,Math.PI*2),e.fill()}),c.tremolo&&ye(18,B=>{for(let ot=-1;ot<=1;ot++)Lt(pt-6,B+ot*4+5.5,pt+6,B+ot*4+.5);e.beginPath();for(let ot=0;ot<=12;ot++)e[ot?"lineTo":"moveTo"](pt-8+16*ot/12,B-7+Math.sin(ot/12*Math.PI*2)*2);e.stroke()})})}const on=(p,c,D,gt)=>{if(e.globalAlpha=p.shown*gt,e.fillStyle=p.fill,p.squeeze===1)return e.fillText(c,p.x+p.left+D,p.y);e.save(),e.translate(p.x,p.y),e.scale(p.squeeze,1),e.fillText(c,p.left+D,0),e.restore()};e.textAlign="left";for(const p of[mt.note,mt.grace]){e.font=p;for(const c of v)c.font===p&&on(c,c.text,0,1)}e.font=mt.finger;for(const p of v)p.finger&&on(p,p.finger,p.textWidth+3,.7);for(const p of nn)p();e.globalAlpha=1,w&&e.restore()};if(!_)we(null);else if(we([xt-40,dt+4]),Nt){const w=dt+24,Q=j;E=V=>w+(V-Nt.start)*Nt.scale,[$,P,j]=[Nt.start,Nt.start+Ht/Nt.scale,-1/0],we([w-8,st+4]),e.save(),e.globalCompositeOperation="destination-out",e.fillStyle="rgba(0, 0, 0, 0.55)",e.fillRect(w-8,0,st+12-(w-8),Ot),e.restore(),e.strokeStyle=I(o.text,.22),e.lineWidth=1.5,e.setLineDash([3,5]),Lt(dt+12,t-d*.6,dt+12,L+d*.6),e.setLineDash([]),j=Q}e.shadowColor=o.accent,e.shadowBlur=16,e.strokeStyle=o.accent,e.lineWidth=3,Lt(j,t-d*.7,j,L+d*.7);for(const{y:w,c:Q}of vt)e.shadowColor=Q,e.fillStyle="#ffffff",e.beginPath(),e.arc(j,w,4,0,Math.PI*2),e.fill();e.shadowBlur=0,e.globalCompositeOperation="destination-out";for(const[w,Q,V]of _?[]:[[xe+10,1,wi],[M-Be,-1,80]]){const bt=e.createLinearGradient(w,0,w+Q*V,0);bt.addColorStop(0,"rgba(0, 0, 0, 1)"),bt.addColorStop(1,"rgba(0, 0, 0, 0)"),e.fillStyle=bt,e.fillRect(Q>0?0:w-V,0,Q>0?w+V:M-w+V,Ot)}e.globalCompositeOperation="destination-over",e.beginPath(),e.roundRect(Be,R,M-Be*2,Tt-R,16),e.fillStyle=I(o.ink,.72),e.fill(),e.globalCompositeOperation="source-over",e.strokeStyle=o.chipBorder,e.lineWidth=1,e.stroke();const He=`700 ${Me(Math.min(14,d*.24))}px ${o.num}`,je=Math.min(13,d*.22);e.font=He,e.textAlign="center";for(let w=0;w<m&&l.open;w++){const Q=(Be+xe)/2,V=U(w);e.strokeStyle=e.fillStyle=ct(w),e.lineWidth=1.8,e.beginPath(),e.arc(Q,V,je,0,Math.PI*2),e.stroke(),e.fillText($i(l.open[w]),Q,V+Jt(e,He,"E").middle)}}export{Ui as HEADSTOCKS,Zi as bendAt,ho as drawHighway,fo as drawTab,Yi as headstockParts,Ri as lookAhead,no as moveCamera,ai as rounded,ri as spline};
1
+ import{lap as ue}from"./perf.js";import{noteName as $i}from"./music.js";const Ot=900,Li=84,Jn=28,Vn=2.2,Di=.9,Ci=2.4,Ri=a=>Li*(a.drawDistance??1)/(Jn*(a.noteSpeed??1)),_i=.34,$t=24,fn=1.2,Ei=1.25,Oi=1.25,Re=5,cn=1,Bi=1.6,Hi=2,dn=.19,Zn=.12,Qn=3,Ni=11,Fi=[{time:-1/0,endTime:1/0,fret:1,width:4}],Cn=[3,5,7,9,12,15,17,19,21,24],Rn=.15,ti=.31,ei=1.7,ni=1.4,ii=1,oi=1.2,zi=.75,ai=(a,l,f,o,e)=>{const[M,m,d,t]=[Math.min(a,l),Math.max(a,l),Math.min(f,o),Math.max(f,o)],L=Math.min(e,(m-M)/2,(t-d)/2),R=(kt,U,wt)=>{const _=Array.from({length:5},(xt,st)=>[kt+Math.cos(wt+st*Math.PI/8)*L,U+Math.sin(wt+st*Math.PI/8)*L]);return[_[0],..._,_[4]]};return[...R(m-L,t-L,0),...R(M+L,t-L,Math.PI/2),...R(M+L,d+L,Math.PI),...R(m-L,d+L,1.5*Math.PI)]},Gi=a=>[...a,a.at(-1),...a.slice(0,-1).reverse().map(([l,f])=>[l,-f])],Ui={inline:{label:"6 in line",outline:[[0,1],[.42,1.05],[.73,1.3],[1.01,1.53],[1.46,1.45],[2.73,1.08],[4.38,.62],[5.79,.17],[6.54,-.13],[6.88,-.35],[7.03,-.88],[6.98,-1.56],[6.64,-2.11],[6.14,-2.38],[5.59,-2.34],[5.21,-2.05],[4.99,-1.66],[4.75,-1.39],[4.25,-1.3],[3.5,-1.39],[2.6,-1.6],[1.85,-1.81],[1.18,-1.75],[.83,-1.36],[.47,-1.06],[0,-1]],posts:{from:[1.56,.95],to:[6.01,-.58]},keys:"machine",tree:2.47},fourTwo:{label:"4 + 2",outline:[[0,1],[.48,1.03],[.94,1.35],[1.21,1.72],[1.52,1.72],[2.99,1.31],[4.23,.95],[5.53,.57],[5.92,.28],[6.07,-.36],[6.05,-1.03],[5.79,-1.53],[5.36,-1.67],[4.95,-1.53],[4.68,-1.29],[4.36,-1.19],[4.02,-1.32],[3.67,-1.56],[2.99,-1.67],[2.08,-1.6],[1.4,-1.43],[.94,-1.16],[.48,-1.03],[0,-1]],posts:{from:[1.81,1.08],to:[4.94,-.03],treble:{share:1/3,from:[2.33,-1.03],to:[3.38,-.69]}},keys:"machine"},openBook:{label:"3 + 3 open book",outline:Gi([[0,1],[.48,1.07],[.96,1.33],[1.47,1.53],[3.16,1.67],[4.98,1.76],[6.25,1.8],[6.25,1.8],[6.42,.93],[6.3,0]]),posts:{from:[2.5,1.07],to:[5.1,1.07],treble:{share:1/2}},keys:"tulip",cover:[[.22,0],[.22,.4],[.36,.5],[.78,.4],[1.3,.25],[1.82,.16],[2.13,.1],[2.24,0],[2.13,-.1],[1.82,-.16],[1.3,-.25],[.78,-.4],[.36,-.5],[.22,-.4],[.22,0]],screws:[[.43,0],[1.98,0]]},pointed:{label:"3 + 3 pointed",outline:[[0,1],[.36,1.12],[.75,1.47],[1.07,1.84],[1.38,1.93],[2.29,1.73],[3.26,1.55],[4.36,1.35],[5.45,1.12],[5.75,.95],[5.86,.43],[5.98,-.22],[6.29,-.75],[6.75,-1.22],[6.75,-1.22],[6.17,-1.24],[5.33,-1.3],[4.36,-1.37],[3.26,-1.55],[2.29,-1.73],[1.38,-1.93],[1.07,-1.84],[.75,-1.47],[.36,-1.12],[0,-1]],posts:{from:[2.07,1],to:[4.65,.46],treble:{share:1/2}},keys:"machine",cover:[[.1,.44],[.1,.44],[.59,.4],[1.1,.28],[1.69,0],[1.69,0],[1.1,-.28],[.59,-.4],[.1,-.44],[.1,-.44],[.1,.44]],screws:[]},headless:{label:"Headless",outline:ai(.2,.95,-1.06,1.06,.2),clamps:.58}};function Yi(a,l){const f=l.length,o=ri(a.outline,10);let e=l.map(t=>[a.clamps,t]),M=l.map(()=>1);if(a.posts){const{from:t,to:L,treble:R}=a.posts,kt=R?Math.floor(f*R.share+1e-9):0,U=f-kt,wt=(Ht,dt,E)=>j=>Ht.map(($,P)=>$+(dt[P]-$)*j/Math.max(1,E-1)),_=([Ht,dt])=>[Ht,-dt],xt=wt(t,L,U),st=wt(R?.from??_(t),R?.to??_(L),kt);e=l.map((Ht,dt)=>dt<U?xt(dt):st(f-1-dt)),M=l.map((Ht,dt)=>dt<U?1:-1)}const m=(t,L)=>{let R=null;for(let kt=1;kt<o.length;kt++){const[U,wt]=o[kt-1],[_,xt]=o[kt];if((U-t)*(_-t)>0||U===_)continue;const st=wt+(xt-wt)*(t-U)/(_-U);(R===null||st*L>R*L)&&(R=st)}return R??L},d=a.keys?e.map(([t],L)=>({u:t,side:M[L],edge:m(t,M[L])})):[];return{outline:o,ends:e,keys:d}}const si=new WeakMap,Ye=new Map,qi=(a,l)=>{const f=l.join(),o=si.get(a);if(o?.key===f)return o.parts;const e=Yi(a,l);return si.set(a,{key:f,parts:e}),e},li=(a,l)=>(Ye.has(a)||(Ye.size>500&&Ye.clear(),Ye.set(a,l())),Ye.get(a)),ri=(a,l=8)=>[...a.slice(0,-1).flatMap((f,o)=>{const e=a[Math.max(0,o-1)],M=a[o+1],m=a[Math.min(a.length-1,o+2)];return f[0]===M[0]&&f[1]===M[1]?[f]:Array.from({length:l},(d,t)=>{const L=t/l;return[0,1].map(R=>.5*(2*f[R]+(M[R]-e[R])*L+(2*e[R]-5*f[R]+4*M[R]-m[R])*L*L+(3*f[R]-e[R]-3*M[R]+m[R])*L**3))})}),a.at(-1)],_n=(a,l)=>{if(!a.startsWith("#"))return a;const f=o=>{const e=parseInt(a.slice(o,o+2),16);return Math.round(l>0?e+(255-e)*l:e*(1+l)).toString(16).padStart(2,"0")};return`#${f(1)}${f(3)}${f(5)}`},mn=new Map,I=(a,l)=>{if(!a.startsWith("#"))return a;const f=a+l;let o=mn.get(f);return o||(mn.size>1e3&&mn.clear(),mn.set(f,o=`rgba(${parseInt(a.slice(1,3),16)}, ${parseInt(a.slice(3,5),16)}, ${parseInt(a.slice(5,7),16)}, ${l})`)),o},_e=(a,l)=>{let f=0,o=a.length;for(;f<o;){const e=f+o>>1;a[e].time<l?f=e+1:o=e}return f};function hi(a){if(a.links?.next.length===a.notes.length)return a.links;const l=a.notes.length,f=new Array(l).fill(-1),o=new Array(l).fill(-1),e={};let M=0;for(let m=0;m<l;m++){const{string:d,sustain:t}=a.notes[m];e[d]!==void 0&&([o[m],f[e[d]]]=[e[d],m]),e[d]=m,M=Math.max(M,t)}return a.links={next:f,prev:o,held:M}}const Me=a=>Math.round(a*4)/4,Bt=32,gn=new Map;let fi=0;const Jt=(a,l,f)=>{let o=gn.get(l);o||gn.set(l,o=new Map);let e=o.get(f);if(!e){++fi>5e3&&([fi,o]=[0,new Map],gn.clear(),gn.set(l,o)),a.font=l;const M=a.measureText(f);o.set(f,e={width:M.width,middle:(M.actualBoundingBoxAscent-M.actualBoundingBoxDescent)/2,top:M.actualBoundingBoxAscent})}return e},pn=128,En=new WeakMap,Xi=a=>{if(!En.has(a)){const l=new OffscreenCanvas(1,pn),f=l.getContext("2d"),[o,e]=[a.floor0,a.floor1].map(m=>[1,3,5].map(d=>parseInt(m.slice(d,d+2),16))),M=Array.from({length:pn},(m,d)=>{const t=(d+.5)/pn;return`rgba(${o.map((L,R)=>Math.round(L+(e[R]-L)*t))}, ${1-t})`});M.forEach((m,d)=>{f.fillStyle=m,f.fillRect(0,pn-1-d,1,1)}),En.set(a,{strip:l,near:M[0]})}return En.get(a)},Ee=new Map,ci=new WeakMap,di=(a,l,f)=>{let o=ci.get(a);o||ci.set(a,o=new Map);let e=o.get(l);if(!e){e=a.createLinearGradient(0,0,0,1);for(const[M,m]of f)e.addColorStop(M,m);o.set(l,e)}return e},un=new Map,mi=(a,l,f,o,e)=>{const M=`${l}|${f}|${o}|${e}`;let m=un.get(M);return m||(un.size>20&&un.clear(),m=a.createLinearGradient(0,l,0,f),m.addColorStop(0,o),m.addColorStop(1,e),un.set(M,m)),m},Mn=(a,l)=>[a[0]-l[0],a[1]-l[1],a[2]-l[2]],xn=(a,l)=>a[0]*l[0]+a[1]*l[1]+a[2]*l[2],ji=(a,l)=>[a[1]*l[2]-a[2]*l[1],a[2]*l[0]-a[0]*l[2],a[0]*l[1]-a[1]*l[0]],Ki=a=>a.map(l=>l/Math.hypot(...a)),Ji=(a,l)=>{let f=0;for(const o of a??[]){if(o.time>l)break;f=o.fret}return f},qe=(a,l)=>{let f=0,o=a.length;for(;f<o;){const e=f+o>>1;a[e].time<=l?f=e+1:o=e}return a[Math.max(0,f-1)]},gi=a=>a*a*(3-2*a),Vi=.3,pi=new WeakMap;function ui(a,l){let f=pi.get(a);if(f||pi.set(a,f={}),!(l in f)){const o=Math.max(a.sustain,.05),M=(a[l]??(l==="bendCurve"&&a.bend?[[0,0],[.25,a.bend]]:null))?.map(([m,d])=>[m*o,d,!1])??[];M.length&&M[0][0]>.001&&(M[0][2]=!0,M.unshift([0,0,!1])),f[l]=M.length?M:null}return f[l]}function Mi(a,l){if(!a)return 0;let f=a[0][1];for(let o=1;o<a.length&&l>a[o-1][0];o++){const[[e,M],[m,d,t]]=[a[o-1],a[o]],L=Math.min(m-e,Vi)||1e-6;f=M+(d-M)*gi(Math.min(1,Math.max(0,(l-(t?m-L:e))/L)))}return f}const Zi=(a,l)=>Mi(ui(a,"bendCurve"),l),Qi=(a,l)=>Mi(ui(a,"whammy"),l),xi=new WeakMap,Oe=a=>{let l=xi.get(a);return l===void 0&&xi.set(a,l=Math.max(a.bend||0,...(a.bendCurve??[]).map(([,f])=>f))),l};function to(a){if(a.chordSpans)return a.chordSpans;const l=[];for(const f of a.chords){const o=Math.max(f.time+.25,...f.notes.map(M=>a.notes[M].time+a.notes[M].sustain)),e=l.at(-1);e&&f.time-e.end<1&&(f.name?f.name===e.name:f.highDensity)?e.end=Math.max(e.end,o):f.name&&l.push({name:f.name,time:f.time,end:o})}for(const f of a.handShapes??[])f.arpeggio&&f.name&&l.push({name:f.name,time:f.startTime,end:f.endTime});return a.chordSpans=l.sort((f,o)=>f.time-o.time)}function eo(a){if(a.chordRails)return a.chordRails;const l=[],f=o=>Math.max(o.time+.15,...o.notes.map(e=>a.notes[e].time+a.notes[e].sustain));for(let o=0;o<a.chords.length;o++){const e=a.chords[o];if(e.highDensity)continue;let M=f(e),m=o+1;for(;a.chords[m]?.highDensity&&a.chords[m].time-M<1;m++)M=Math.max(M,f(a.chords[m]));M=Math.min(M,a.chords[m]?.time??1/0),M-e.time>.2&&l.push({time:e.time,end:M,frets:e.notes.map(d=>a.notes[d].fret)})}for(const o of a.handShapes??[])o.arpeggio&&l.push({time:o.startTime,end:o.endTime,frets:o.frets,arpeggio:o});return a.chordRails=l}const bi={artificial:"AH",pinch:"PH",tap:"TH",semi:"SH",feedback:"FH"},yi=a=>a<.5?"¼":a===.5?"½":a===1?"full":a%1?`${Math.floor(a)}½`:String(a),Si=(a,l,f,o)=>{if(a===void 0)return l;const e=a+(l-a)*(1-Math.exp(-f/o));return Math.abs(l-e)<1e-6?l:e};function ki(a,l,f,o,e){a[l]===void 0&&([a[l],a[l+"Speed"]]=[f,0]);const M=2/o,m=M*e,d=1/(1+m+.48*m*m+.235*m*m*m),t=a[l]-f,L=(a[l+"Speed"]+M*t)*e;a[l+"Speed"]=(a[l+"Speed"]-M*L)*d,a[l]=f+(t+L)*d,Math.abs(a[l]-f)<1e-6&&Math.abs(a[l+"Speed"])<1e-6&&([a[l],a[l+"Speed"]]=[f,0])}function Ti(a,l,f=0){let o=1/0,e=-1/0;for(const m of a)m.endTime<=l||m.time>=l+Qn||(o=Math.min(o,m.fret-1),e=Math.max(e,m.fret-1+m.width));if(o===1/0){const m=qe(a,l);[o,e]=[m.fret-1,m.fret-1+m.width]}f&&(o=Math.min(o,f-1));const M=Math.max(Ni,e-o+2)+1;return{lo:o,hi:e,span:M,center:Math.min(25-M/2,Math.max(M/2-1,(o+e)/2))}}function no(a,l,f,o,e=0){const M=Ti(l,f,e),m=a.target,d=!m||M.lo<m.center-m.span/2||M.hi>m.center+m.span/2,t=m&&m.span-Math.max(M.span,Ti(l,f+Qn,e).span)>2;(d||t)&&(a.target=M);const L=Math.min(o-(a.at??o),100);a.at=o,ki(a,"span",a.target.span,a.target.span>a.span?.8:1.4,L/1e3),ki(a,"center",a.target.center,1,L/1e3);const R=qe(l,f);return a.left=Si(a.left,R.fret-1,L,90),a.right=Si(a.right,R.fret-1+R.width,L,90),R}function Ai(a,l,f,o,e,M,m,d){a.beginPath(),a.moveTo(l-o,f-M*e),a.lineTo(l,f),a.lineTo(l+o,f-M*e),a.lineWidth=Math.max(3,e*1.15),a.strokeStyle=d,a.stroke(),a.lineWidth=Math.max(1.5,e*.65),a.strokeStyle=m,a.stroke(),a.lineWidth=Math.max(.6,e*.2),a.strokeStyle="rgba(255, 255, 255, 0.5)",a.stroke()}function Xe(a,l,f,o,e){a.beginPath(),a.moveTo(l,f),a.lineTo(o,e),a.stroke()}function Pi(a){const l=devicePixelRatio||1,f=a.clientWidth,o=a.clientHeight;(a.width!==Math.round(f*l)||a.height!==Math.round(o*l))&&(a.width=Math.round(f*l),a.height=Math.round(o*l));const e=a.getContext("2d"),M=o/Ot,m=f/M,d=l*M;return e.setTransform(d,0,0,d,0,0),e.clearRect(0,0,m,Ot),{g:e,W:m,B:d}}function ho(a,l,f,o,e){const{g:M,W:m,B:d}=Pi(a);let t=M;if(!l)return;const L=l.anchors.length?l.anchors:Fi,R=Ji(l.capos,f),kt=no(e,L,f,performance.now(),R),U=l.strings,wt=Math.min(.5,5*_i/Math.max(1,U-1)),_=wt*Oi*(o.boardHeight??1),xt=_*(U-1),st=n=>(o.stringOrder==="high"?n:U-1-n)*_,Ht=n=>(n>=U/2?1:-1)*(o.stringOrder==="high"?-1:1),dt=Jn*(o.noteSpeed??1),E=Ri(o),j=-.22,$=xt+.22,P=j-.06,Nt=E*dt,ct=n=>Math.max(0,n)*dt,Ft=n=>o.str[n%o.str.length],Lt=o.noteLines===0?null:`rgba(255, 255, 255, ${o.noteLines??.5})`,he=+o.fretNumbers||0,Vt=e.span,vt=[e.center,wt*(U-1)/2,0],we=(o.viewAngle??30)*Math.PI/180,He=.6*Math.SQRT2*Vt,je=[vt[0],xt+He*Math.sin(we),-He*Math.cos(we)],w=Ki(Mn([vt[0],0,2.2*Vt],je)),Q=ji(w,[1,0,0]),V=(o.sideAngle??0)*Math.PI/180,[bt,Ct]=[Math.sin(V),Math.cos(V)],te=Mn(je,vt),zt=xn(te,w),ve=xn(te,Q),Rt=[-bt,w[1]*Ct,w[2]*Ct],be=[Ct,w[1]*bt,w[2]*bt],Gt=[vt[0]+ve*Q[0]+zt*Rt[0],vt[1]+ve*Q[1]+zt*Rt[1],ve*Q[2]+zt*Rt[2]],Ke=Math.min(m*.88,Ot*(o.fill?1.3:1.05)),Je=Ke*xn(Mn(vt,Gt),Rt)/Vt,mt=Math.min(Ei*(o.fretWidth??1),m*Vt/(Ke*Math.max(1,Vt-2.5)));let Ve=0,Ne=0;const[bn,yn,Ze]=Gt,[Fe,ye,Sn]=Rt,[Se,kn,Qe]=be,[Tn,tn,en]=Q,v=(n,i,h)=>{const s=n-bn,r=i-yn,g=h-Ze,u=Je/Math.max(.05,s*Fe+r*ye+g*Sn);return[m/2+(s*Se+r*kn+g*Qe)*mt*u+Ve,Ot/2-(s*Tn+r*tn+g*en)*u+Ne,u]},[nn,on,p]=v(...vt);[Ve,Ne]=[m/2-nn,Ot*(o.fill?.83:.81)-on];const[,c]=v(e.center-Vt/2,P,0),[,D]=v(e.center+Vt/2,P,0),[,gt]=v(e.center,P,0);Ne-=Math.min(Ot*.08,Math.max(0,c-gt,D-gt)),ue("setup");const A=(n,i=!0)=>{t.beginPath();for(let h=0;h<n.length;h++){const[s,r]=v(n[h][0],n[h][1],n[h][2]);h?t.lineTo(s,r):t.moveTo(s,r)}i&&t.closePath()},H=(n,i)=>{A([n,i],!1),N()},Tt=(n,i,h,s,r)=>{if(o.gem!=="pill")return A([[n-s,i-r,h],[n+s,i-r,h],[n+s,i+r,h],[n-s,i+r,h]]);const[g,u]=v(n-s,i,h),[S,x]=v(n+s,i,h),[,k]=v(n,i+r,h),[,J]=v(n,i-r,h),F=Math.atan2(x-u,S-g),z=Math.min(Math.abs(J-k),Math.hypot(S-g,x-u))/2,[W,O]=[z*Math.cos(F),z*Math.sin(F)];t.beginPath(),t.arc(g+W,u+O,z,F+Math.PI/2,F+Math.PI*1.5),t.arc(S-W,x-O,z,F-Math.PI/2,F+Math.PI/2),t.closePath()},rt=(n,i)=>{const h=qe(L,i),s=n.filter(r=>r>0);return[Math.min(h.fret-1,...s.map(r=>r-1))+.05,Math.max(h.fret-1+Math.max(4,h.width),...s)-.05]},fe=(n,i,h,s,r)=>{H([n-s,i-r,h],[n+s,i+r,h]),H([n-s,i+r,h],[n+s,i-r,h])},We=o.markings==="white",Zt=We?"#ffffff":o.ink,Ie=(n,i,h,s,r,g,u,S=null)=>{const[x,k]=u?[r*.85,g*.8]:[Math.min(r,.34)*.4,g*.55],J=u&&!We&&!S;S||(t.strokeStyle=I(o.ink,J?.85:.7),t.lineWidth=J?Math.max(2,.06*s):Math.max(3.5,.1*s),fe(n,i,h,x,k)),!J&&(t.strokeStyle=S??"#ffffff",t.lineWidth=Math.max(S?2:1.8,.05*s),fe(n,i,h,x,k))};let Qt=null,_t=0;const ke=n=>{n!==Qt&&(t.font=Qt=n)},ce={},oe=(n,i,h,s,r,g)=>{const u=ce[r]??=`${r} ${Bt}px ${o.num}`,S=s/Bt;return Jt(t,u,n),ke(u),t.textAlign=g,t.setTransform(d*S,0,0,d*S,d*i,d*(h-_t)),Jt(t,u,n).middle},Ut=()=>t.setTransform(d,0,0,d,0,-d*_t),ze=(n,i,h)=>{t.fillStyle=n,t.setTransform(d,0,0,d*(h-i),0,d*(i-_t)),t.fill(),Ut()},At=(n,i,h,s,r,g,u=700,S="center",x=!0,k=!1)=>{const[J,F,z]=v(i,h,s),W=r*(k?z:Math.sqrt(z*p));if(W<(k?1:8)||J<-60||J>m+60)return;t.textBaseline="alphabetic";const O=oe(n,J,F,W,u,S);x&&(t.lineWidth=Bt*.2,t.strokeStyle=I(o.ink,.9),t.strokeText(n,0,O)),t.fillStyle=g,t.fillText(n,0,O),Ut(),t.textBaseline="middle"},ee=(n,i,h,s,r,g,u=700)=>{const[S,x,k]=v(i,P,h),J=(p/k)**zi,[F,z]=v(i+s*J,P,h),W=Math.hypot(F-S,z-x);let O=r*J,[lt,nt]=v(i,P,h+O),X=Math.hypot(lt-S,nt-x);for(let et=0;et<3&&X>W*oi;et++)O*=W*oi/X,[lt,nt]=v(i,P,h+O),X=Math.hypot(lt-S,nt-x);const at=Math.abs(Math.atan2(lt-S,x-nt));if(S<-60||S>m+60||X<ii||at>ni)return;const b=t.globalAlpha;t.globalAlpha=b*Math.min(1,(ni-at)/.2,(X-ii)/3);const St=ce[u]??=`${u} ${Bt}px ${o.num}`;ke(St),t.textAlign="center",t.textBaseline="alphabetic";const{top:It}=Jt(t,St,n);t.setTransform(d*(F-S)/Bt,d*(z-x)/Bt,-d*(lt-S)/Bt,-d*(nt-x)/Bt,d*S,d*(x-_t)),t.fillStyle=g,t.fillText(n,0,It),Ut(),t.globalAlpha=b,t.textBaseline="middle"},[,pt]=v(vt[0],P,0),[,$e]=v(vt[0],P,Nt),Wt=(n,i,h)=>{const s=`${pt}|${$e}`;(Ee.span!==s||Ee.size>300)&&(Ee.clear(),Ee.span=s);const r=`${n}|${i}|${h}`;let g=Ee.get(r);return g||(g=t.createLinearGradient(0,pt,0,$e),g.addColorStop(0,I(n,i)),g.addColorStop(1,I(n,h)),Ee.set(r,g)),g};let Yt=null;const tt=(n,i,h=10,s=!1)=>Yt=n?{color:i,blur:h,faded:s}:null,An=[[.6,.05],[.35,.13],[.15,.27]],de=[[.4,.3]],ae=n=>{if(!Yt)return;const{lineWidth:i,globalAlpha:h}=t,s=n?1:Math.min(1,2*i/Yt.blur);t.save(),t.strokeStyle=Yt.faded?Wt(Yt.color,1,.1):Yt.color;for(const[r,g]of Yt.blur>4?An:de)t.lineWidth=(n?0:i)+2*Yt.blur*r,t.globalAlpha=h*g*s,t.stroke();t.restore()},N=()=>{ae(!1),t.stroke()},Y=()=>{ae(!0),t.fill()};t.textBaseline="middle",t.lineCap="round",t.lineJoin="round";const{strip:se,near:B}=Xi(o);let[ot,ft]=[-60,$t+60];if(V){const n=vt[0]+(1-xn(Mn([vt[0],P,0],Gt),Rt))/Rt[0];[ot,ft]=Rt[0]>0?[Math.max(-60,n),$t+60]:[-60,Math.min($t+60,n)]}t.save(),A([[ot,P,0],[ft,P,0],[ft,P,Nt],[ot,P,Nt]]),t.clip(),V&&(t.fillStyle=B,t.fillRect(0,pt,m,Ot-pt)),t.imageSmoothingEnabled=!1,t.drawImage(se,0,$e,m,pt-$e),t.restore();const ut=(n,i)=>{const[h,s]=v(...n),[r,g]=v(...i);t.moveTo(h,s),t.lineTo(r,g)};t.strokeStyle=Wt(o.lane,.5,.04),t.lineWidth=Di,t.beginPath();for(let n=0;n<=$t;n++)ut([n,P,0],[n,P,Nt]);N();for(const n of[!1,!0]){t.strokeStyle=n?o.measure:o.beat,t.lineWidth=n?1.6:1,t.beginPath();const i=[];for(let h=_e(l.beats,f);h<l.beats.length;h++){const s=l.beats[h],r=s.time-f;if(r>E)break;s.measure>=0===n&&(r>E-.4?i.push(r):ut([0,P,ct(r)],[$t,P,ct(r)]))}N();for(const h of i)t.globalAlpha=(E-h)/.4,t.beginPath(),ut([0,P,ct(h)],[$t,P,ct(h)]),N();t.globalAlpha=1}if(he)for(let n=_e(l.beats,f);n<l.beats.length;n++){const i=l.beats[n],h=i.time-f;if(h>E)break;if(i.measure<0)continue;const s=qe(L,i.time),r=ct(h);t.globalAlpha=Math.min(1,(E-h)/.4);for(const g of Cn)(g<s.fret||g>=s.fret+s.width)&&ee(String(g),g-.5,r,ti,ei,I(o.inlay,he))}t.globalAlpha=1,(o.guides===!1?[]:L.filter(n=>n.endTime>f&&n.time<f+E)).forEach((n,i)=>{const h=ct(Math.max(0,n.time-f)),s=ct(Math.min(E,n.endTime-f)),r=n.fret-1,g=r+n.width;t.fillStyle=Wt(o.anchorFill,o.anchorOpacity,.02),A([[r,P,h],[g,P,h],[g,P,s],[r,P,s]]),Y(),t.strokeStyle=Wt(o.anchorLane,.55,.04),t.lineWidth=Ci*.6;for(const u of[r,g])H([u,P,h],[u,P,s]);i&&n.time>f&&H([r,P,h],[g,P,h])});const Te=new Map,ie=n=>{const i=Math.round(n*100);return Te.has(i)||Te.set(i,{dt:n-f,texts:[],pins:[]}),Te.get(i)};for(const n of l.markers??[])n.time>=f&&n.time<=f+E&&!ie(n.time).texts.includes(n.text)&&ie(n.time).texts.push(n.text);for(const n of l.hairpins??[])n.time>=f&&n.time<=f+E&&ie(n.time).pins.push(n.kind);const vi=Math.min(e.center-(e.span/2+.5)/mt,-.5);for(const{dt:n,texts:i,pins:h}of Te.values()){const[s,r,g]=v(vi,P,ct(n)),u=Math.sqrt(g*p),S=i.join(" · "),x=.25*u,k=`700 ${Bt}px ${o.num}`,J=.3*u/Bt,F=S?Jt(t,k,S).width*J:0,z=F+h.length*(.9*u+x);ke(k);let W=Math.max(s-.3*u,16+z);t.globalAlpha=Math.min(1,(E-n)/.4),S&&(t.save(),t.translate(W,r),t.scale(J,J),t.textAlign="right",t.lineWidth=Bt*.2,t.strokeStyle=I(o.ink,.9),t.strokeText(S,0,0),t.fillStyle=o.accent,t.fillText(S,0,0),t.restore(),W-=F+x);for(const O of h){const lt=W-.9*u,nt=.14*u,[X,at]=O==="cresc"?[lt,W]:[W,lt];for(const[b,St]of[[I(o.ink,.9),Math.max(3.5,.12*u)],[o.text,Math.max(1.5,.05*u)]])t.strokeStyle=b,t.lineWidth=St,t.beginPath(),t.moveTo(at,r-nt),t.lineTo(X,r),t.lineTo(at,r+nt),N();W=lt-x}}t.globalAlpha=1,ue("floor");const qt=[];for(let n=_e(l.notes,f-hi(l).held-.3);n<l.notes.length;n++){const i=l.notes[n];if(i.time>f+E)break;const h=Math.max(i.sustain,(i.slideTo??i.slideUnpitchTo??null)===null?0:.25,.15);i.time+h>=f-.05&&qt.push(i)}const me=n=>n.chord===null||n.chord===void 0?null:l.chords[n.chord],Pn=n=>o.repeatMarks==="frame"&&(n.repeat||me(n)?.highDensity),ge=n=>{const i=qe(L,n.time),h=n.fret===0;return{a:i,open:h,x:h?i.fret-1+i.width/2:n.fret-.5,y:st(n.string)}},an=(n,i,h)=>{const s=n.slideTo??n.slideUnpitchTo??null,r=Math.min(1,Math.max(0,h/Math.max(n.sustain,.25)));return s===null||n.fret===0?i:i+(s-.5-i)*r*r*(3-2*r)},On=(n,i)=>(Zi(n,i)*Ht(n.string)+Qi(n,i))*_*cn,Bn=n=>{const i=f-n.time;return i<0||n.fret===0||!(Oe(n)>0)?0:On(n,Math.min(i,Math.max(n.sustain,.15)))},sn=new Map;for(const n of qt){const i=n.time-f,h=Math.max(n.sustain,.15);i>0||-i>h||n.fret===0||!(Oe(n)>0)||sn.set(n.string,{note:n,x:n.fret-.5,dy:Bn(n)})}const wn=(n,i=0,h=!1)=>{const s=sn.get(n),r=st(n)+i,g=h?[[0,r,0]]:[rn?[rn[n][0],rn[n][1]+i,0]:[-.6,r,0],[0,r,0]];if(!s)return A([...g,[$t+.6,r,0]],!1);A([...g,[s.x,r+s.dy,0],[$t+.6,r,0]],!1)},ln=n=>st(n.string)+Bn(n),Xt=Ui[o.headstock],Ae=($-j)/2,vn=o.stringOrder==="high"?-1:1,le=([n,i])=>[-n*Ae/mt,xt/2+i*Ae*vn,0],Wn=n=>(st(n)-xt/2)*vn/Ae,jt=Xt&&qi(Xt,Array.from({length:U},(n,i)=>Wn(i))),rn=jt?.ends.map(le),yt=(n,i,h=1)=>{n&&(t.fillStyle=n,Y()),i&&(t.strokeStyle=i,t.lineWidth=h,N())},Pe=(n,i,h)=>{const[s,r]=le(n),[g,u]=v(s,r,0),[S]=v(s+i*Ae/mt,r,0),[,x]=v(s,r+h*Ae,0);t.beginPath(),t.ellipse(g,u,Math.abs(S-g),Math.abs(x-u),0,0,Math.PI*2)},Le=(n,i,h,s,r)=>A(li(`${n},${i},${h},${s},${r}`,()=>ai(n,i,h,s,r)).map(le)),Hn=()=>{for(const{u:h,side:s,edge:r}of jt.keys){const g=(u,S)=>[r+s*u,r+s*S];Xt.keys==="machine"?(Le(h-.15,h+.15,...g(-.12,.08),.03),yt(I(o.text,.12),I(o.anchorLane,.35)),Le(h-.03,h+.03,...g(.06,.22),0),yt(I(o.text,.28)),Le(h-.11,h+.11,...g(.2,.68),.1),yt(I(o.text,.18),I(o.anchorLane,.55))):(Le(h-.035,h+.035,...g(-.05,.22),0),yt(I(o.text,.28)),Pe([h,r+s*.18],.08,.04),yt(I(o.text,.3)),Pe([h,r+s*.4],.14,.2),yt(I(o.text,.18),I(o.anchorLane,.55)))}A(jt.outline.map(le));const[,n]=v(...le([0,1.6])),[,i]=v(...le([0,-1.2]));if(yt(mi(t,n,i,o.floor0,o.ink)),t.save(),t.clip(),yt(null,I(o.text,.07),.3*Ae*p),t.restore(),tt(!0,o.anchorLane,8),yt(null,I(o.anchorLane,.6),Math.max(1.5,.03*p)),tt(!1),Xt.cover){A(li(Xt.cover,()=>ri(Xt.cover)).map(le)),yt(I(o.text,.09),I(o.text,.4));for(const h of Xt.screws)Pe(h,.04,.04),yt(I(o.nut,.85))}},Nn=n=>Vn*(.7+.14*(U-1-n)),Wi=()=>{if(e.plate?.key!==In||e.plate.t!==o)return e.plate={key:In,t:o},Hn();const n=e.plate;if(!n.image){const[i,h]=[[],[]];for(const J of[...jt.outline,...jt.keys.map(({u:F,side:z,edge:W})=>[F,W+z*.8])]){const[F,z]=v(...le(J));i.push(F),h.push(z)}const s=Math.floor(Math.max(0,Math.min(...i)-24)*d)/d,r=Math.min(m,Math.max(...i)+24),g=Math.floor(Math.max(0,Math.min(...h)-24)*d)/d,u=Math.min(Ot,Math.max(...h)+24);n.image=new OffscreenCanvas(Math.max(1,Math.ceil((r-s)*d)),Math.max(1,Math.ceil((u-g)*d)));const[S,x,k]=[t,_t,Qt];[t,_t,Qt,n.x,n.y]=[n.image.getContext("2d"),0,null,s,g],t.setTransform(d,0,0,d,-s*d,-g*d),t.lineCap=t.lineJoin="round",Hn(),[t,_t,Qt]=[S,x,k]}t.drawImage(n.image,n.x,n.y,n.image.width/d,n.image.height/d)},Fn=()=>{t.fillStyle=o.board,A([[0,j,0],[$t+.6,j,0],[$t+.6,$,0],[0,$,0]]),Y(),t.fillStyle=I(o.anchorFill,.16),A([[e.left,j,0],[e.right,j,0],[e.right,$,0],[e.left,$,0]]),Y(),t.fillStyle=o.inlayDot;const n=s=>(Math.max(0,Math.ceil(s)-1)+.5)*_;t.beginPath();for(const s of Cn)for(const r of s%12?[n((U-1)/2)]:[n((U-1)/4),xt-n((U-1)/4)]){const[g,u,S]=v(s-.5,r,0);t.moveTo(g+.1*S,u),t.ellipse(g,u,.1*S,.08*S,0,0,Math.PI*2)}Y(),R>0&&(t.fillStyle=I(o.ink,.5),A([[0,j,0],[R-Rn,j,0],[R-Rn,$,0],[0,$,0]]),Y()),jt&&Wi();const[,i]=v(vt[0],$,0),[,h]=v(vt[0],j,0);t.strokeStyle=mi(t,i,h,I(o.anchorPost,.75),o.post),t.lineWidth=Math.max(1.5,.05*p),t.beginPath();for(let s=1;s<=$t;s++)ut([s,j-.04,0],[s,$+.04,0]);N(),t.strokeStyle=o.nut,t.lineWidth=Math.max(3,.12*p),H([0,j-.06,0],[0,$+.06,0]),tt(!0,o.anchorPost,12),t.strokeStyle=o.anchorPost,t.lineWidth=Math.max(3,.07*p);for(const s of[e.left,e.right])H([s,j-.14,0],[s,$+.14,0]);tt(!1);for(let s=0;s<U;s++){const r=Nn(s);tt(!0,Ft(s),3),t.strokeStyle=I(Ft(s),.9),t.lineWidth=r,wn(s),N(),tt(!1),t.strokeStyle="rgba(255, 255, 255, 0.25)",t.lineWidth=Math.max(.6,r*.3),wn(s,.012),N()}if(jt&&(jt.ends.forEach(([s,r],g)=>{if(Xt.clamps)Le(s-.1,s+.1,r-.1,r+.1,.04),yt(I(o.text,.22),I(o.text,.45)),Pe([s,r],.05,.05),yt(o.nut);else{Pe([s,r],.17,.17),yt(I(o.ink,.5),I(o.nut,.4)),Pe([s,r],.085,.085),yt(o.nut),Pe([s,r],.03,.03),yt(I(o.ink,.85));const[u,S,x]=v(...rn[g]),[k,J]=v(0,st(g),0),F=Math.atan2(J-S,k-u);t.beginPath(),t.arc(u,S,.1*Ae*x,F-1.3,F+1.3),yt(null,Ft(g),Nn(g))}}),Xt.tree)){const s=[U-2,U-1].map(r=>{const[g,u]=jt.ends[r];return Wn(r)+(u-Wn(r))*Xt.tree/g});Le(Xt.tree-.05,Xt.tree+.05,Math.min(...s)-.08,Math.max(...s)+.08,.04),yt(I(o.nut,.7),I(o.ink,.6))}for(const s of[!1,!0])for(let r=1;r<=$t;r++){const g=r>=kt.fret&&r<kt.fret+kt.width,u=Cn.includes(r);(g||u)===s&&At(String(r),r-.5,j-.3,0,g?.3:u?.26:.2,g?o.accent:u?o.inlay:o.numOff,s?800:500,"center",!1)}},Ge=(n,i)=>v(n,i,0).slice(0,2).map(h=>Math.round(h*d*10)).join(":"),In=[o.headstock,U,_,vn,m,d,Math.round(mt*1e4),Ge(0,j),Ge($t,j),Ge(0,$),Ge($t,$),Ge(-4,xt/2)].join(),hn=!sn.size&&[In,kt.fret,kt.width,R,Math.round(e.left*1e3),Math.round(e.right*1e3)].join();if(!hn||e.board?.key!==hn||e.board.t!==o)e.board=hn&&{key:hn,t:o},Fn();else{const n=e.board;if(!n.drawn){const i=[[0,$+.2],[$t,$+.2],[0,j-.9],[$t,j-.9]].map(([u,S])=>v(u,S,0)[1]);jt&&i.push(...[...jt.outline,...jt.keys.map(({u,side:S,edge:x})=>[u,x+S*.8])].map(u=>v(...le(u))[1]));const h=Math.floor(Math.max(0,Math.min(...i)-24)*d)/d,s=Math.min(Ot,Math.max(...i)+24),[r,g]=[Math.ceil(m*d),Math.max(1,Math.ceil((s-h)*d))];(e.boardImage?.width!==r||e.boardImage.height!==g)&&(e.boardImage=new OffscreenCanvas(r,g)),[t,_t,Qt,n.y,n.drawn]=[e.boardImage.getContext("2d"),h,null,h,!0],t.setTransform(1,0,0,1,0,0),t.clearRect(0,0,r,g),Ut(),t.lineCap=t.lineJoin="round",t.textBaseline="middle",Fn(),[t,_t,Qt]=[M,0,null]}t.drawImage(e.boardImage,0,n.y,e.boardImage.width/d,e.boardImage.height/d)}ue("board");const zn=(n,i)=>n.letRing&&-i>.25;for(const n of qt){const i=n.time-f;if(i>0||-i>Math.max(n.sustain,.15)||n.mute)continue;const h=Ft(n.string),s=ln(n);if(tt(!zn(n,i),h,10),t.strokeStyle=h,t.lineWidth=Vn+3,wn(n.string,0,!0),N(),tt(!1),-i<.2){const[r,g,u]=v(ge(n).x,s,0);t.save(),t.translate(r,g),t.scale(1,.4);const S=t.createRadialGradient(0,0,0,0,0,.5*u);S.addColorStop(0,I(o.flash,.8*(1+i/.2))),S.addColorStop(1,I(o.flash,0)),t.fillStyle=S,t.beginPath(),t.arc(0,0,.5*u,0,Math.PI*2),Y(),t.restore()}}t.strokeStyle=o.anchorLane,t.lineWidth=2.5,tt(!0,o.anchorLane,10);for(const n of l.handShapes??[]){if(n.startTime>f||n.endTime<=f||n.endTime-n.startTime<.3||!n.frets.some((s,r)=>s>=0&&r<U))continue;const[i,h]=rt(n.frets.filter((s,r)=>r<U),n.startTime);A([[i,j,0],[h,j,0],[h,$,0],[i,$,0]]),N()}if(tt(!1),R>0){const n=R-Rn;t.strokeStyle=o.nut,t.lineWidth=Math.max(4,.17*p),H([n,j-.16,0],[n,$+.16,0]),t.strokeStyle=I(o.ink,.45),t.lineWidth=Math.max(1,.05*p),H([n,j-.13,0],[n,$+.13,0])}ue("strings");for(const n of qt){const i=n.time-f,h=ct(i),s=me(n),{a:r,open:g,x:u,y:S}=ge(n),x=an(n,u,-i);if(i<-.15||Math.abs(v(x,S,h)[0]-m/2)>m/2+200)continue;const k=g?(r.width-.2)/2:.34;t.globalAlpha=i<0?Math.max(0,1+i/.15):Math.min(1,(E-i)/.4),!s&&Lt&&(t.strokeStyle=Lt,t.lineWidth=2,H([x-k,P,h],[x+k,P,h])),!(g||Pn(n))&&(t.strokeStyle=I(Ft(n.string),n.repeat||s?.highDensity?.35:.75),t.lineWidth=1.5,H([x,Math.min(S,ln(n))-.42*_,h],[x,P,h]))}t.globalAlpha=1;const Gn=(n,i,h)=>{const s=Array.from({length:13},(r,g)=>{const u=g/12;return[n[0]+(i[0]-n[0])*u,n[1]+(i[1]-n[1])*u+Math.sin(Math.PI*u)*h,n[2]+(i[2]-n[2])*u]});A(s,!1),N()};for(const n of eo(l)){if(n.end<=f||n.time>=f+E)continue;const[i,h]=rt(n.frets,n.time),s=n.time-f,r=ct(Math.max(s,0)),g=ct(Math.min(n.end-f,E));t.globalAlpha=Math.min(1,(E-Math.max(s,0))/.4),tt(!n.arpeggio,o.anchorLane,10,!0),t.strokeStyle=Wt(o.anchorLane,1,.2),t.lineWidth=3.5;for(const u of[i,h])H([u,P,r],[u,P,g]);tt(!1),n.arpeggio&&s>0&&(t.strokeStyle=I(o.anchorLane,.7),t.lineWidth=1.5,A([[i,P,r],[i,$,r],[h,$,r],[h,P,r]],!1),N(),n.arpeggio.name&&r>Re&&At(n.arpeggio.name,i-.12,$/2,r,.34,o.text,600,"right"))}t.globalAlpha=1;const $n=(n,i)=>{const h=ge(n);return Math.abs(h.x-i)<(h.open?(h.a.width-.2)/2+.1:.45)};for(const[n,i]of qt.entries()){const h=i.time-f,s=me(i),r=i.slideTo??i.slideUnpitchTo??null,{a:g,open:u,x:S,y:x}=ge(i),k=Ft(i.string),J=ct(h),F=(u?(g.width-.2)/2:.34)*(i.grace?.6:1),z=(u?.12:.42)*_*(i.grace?.6:1);if(h>-.15&&!s?.highDensity&&!i.repeat){if(t.globalAlpha=Math.min(1,(E-h)/.4),t.strokeStyle=k,t.lineWidth=2,t.setLineDash([4,4]),i.slideIn&&H([S+(i.slideIn==="below"?-1.4:1.4),x-z,Math.max(0,J-1)],[S+(i.slideIn==="below"?-F:F),x,J]),i.slideOut&&H([S+(i.slideOut==="up"?F:-F),x,J],[S+(i.slideOut==="up"?1.4:-1.4),x-z,J+1]),t.setLineDash([]),typeof i.tieTo=="number"){const G=l.notes[i.tieTo],q=ge(G);t.setLineDash([5,4]),Gn([S,x+z,J],[q.x,q.y+z,ct(G.time-f)],_*.9),t.setLineDash([])}t.globalAlpha=1}const W=r===null?i.sustain:Math.max(i.sustain,.25),O=r!==null||i.bend||i.bendCurve||i.whammy;if(W<=.2||h+W<=0||s&&!O||Pn(i))continue;u&&r&&(t.strokeStyle=k,t.lineWidth=2.5,t.setLineDash(i.letRing?[7,6]:[]),Gn([S,x,ct(Math.max(h,0))],[r-.5,x,ct(Math.min(h+W,E))],_*1.5),t.setLineDash([]));let lt=null;for(let G=n+1;G<qt.length&&qt[G].time<=i.time+W+.02;G++){const q=qt[G];if(!(q.time<=i.time+.005)&&(me(q)||q.string===i.string||$n(q,S))){lt=q;break}}const nt=Math.max(h,0),X=i.bend||i.bendCurve||i.whammy;let at=Math.min(h+W,E,lt?lt.time-f:1/0);if(at<=nt)continue;const b=G=>{const q=G-h,it=ct(G),y=i.bend||i.bendCurve||i.whammy,T=i.vibrato&&!y?Math.sin(it/1.6*Math.PI*2)*_*(i.vibratoWide?.45:.25):0,C=i.tremolo?Math.floor(it/.3)%2?.05:-.05:0,Z=cn+(Bi-cn)*gi(Math.min(1,it/Hi));return[an(i,S,q)+C,x+T+On(i,q)*Z/cn,it]},St=lt&&b(at)[0],It=lt&&me(lt)?.notes.find(G=>$n(l.notes[G],St)),et=typeof It=="number"?l.notes[It]:lt;if(lt&&(X||$n(et,St))){const G=ge(et),q=ct(et.time-f),it=G.open?(G.a.width-.2)/2:.34,y=v(G.x,G.y-(G.open?.12:.42)*_,q)[1]+3,[T]=v(G.x-it,G.y,q),[C]=v(G.x+it,G.y,q),Z=K=>{const[Pt,pe]=v(...b(K));return pe<y&&Pt>Math.min(T,C)-2&&Pt<Math.max(T,C)+2};if(Z(at)&&!Z(nt)){let K=nt,Pt=at;for(let pe=0;pe<24;pe++)[K,Pt]=Z((K+Pt)/2)?[K,(K+Pt)/2]:[(K+Pt)/2,Pt];at=K}if(at<=nt+.001)continue}const De=r===null&&!X&&!i.vibrato&&!i.tremolo?1:Math.min(400,Math.max(12,Math.ceil((at-nt)*dt*8))),Mt=Array.from({length:De+1},(G,q)=>b(nt+(at-nt)*q/De));if(u&&!s){t.fillStyle=Wt(k,i.letRing?.14:.26,.03),A([...Mt.map(([G,q,it])=>[G-F,q,it]),...Mt.slice().reverse().map(([G,q,it])=>[G+F,q,it])]),Y(),tt(!i.letRing,k,6,!0),t.strokeStyle=Wt(k,.95,.3),t.lineWidth=2.5,t.setLineDash(i.letRing?[7,6]:[]);for(const G of[-F,F])A(Mt.map(([q,it,y])=>[q+G,it,y]),!1),N();t.setLineDash([]),tt(!1)}else if(i.bend||i.bendCurve||i.whammy){const G=q=>A([...Mt.map(([it,y,T])=>[it-q,y,T]),...Mt.slice().reverse().map(([it,y,T])=>[it+q,y,T])]);G(dn),t.fillStyle=Wt(k,1,.6),Y(),G(dn*.35),t.fillStyle=Wt(_n(k,-.22),1,.55),Y(),tt(!0,k,8,!0),t.strokeStyle=Wt(_n(k,.6),1,.5),t.lineWidth=2;for(const q of[-dn,dn])A(Mt.map(([it,y,T])=>[it+q,y,T]),!1),N();tt(!1)}else tt(!i.letRing,k,6,!0),t.fillStyle=Wt(k,i.letRing?.4:.75,i.letRing?.15:.3),A([...Mt.map(([G,q,it])=>[G-.09,q,it]),...Mt.slice().reverse().map(([G,q,it])=>[G+.09,q,it])]),Y(),tt(!1);if((i.letRing||r!==null||!X&&(i.vibrato||i.tremolo))&&(t.strokeStyle=Wt(i.letRing?k:"#ffffff",.75,.3),t.lineWidth=i.letRing?2:1.5,t.setLineDash(i.letRing?[7,6]:[]),A(Mt,!1),N(),t.setLineDash([])),r!==null&&at>=Math.min(h+W,E)-.001){const[G,q,it]=b(h+W);t.strokeStyle=k,t.lineWidth=2,t.setLineDash(i.slideTo===null?[5,4]:[]),u?Tt(r-.5,q,it,.34,.42*_):Tt(G,q,it,F,z),N(),t.setLineDash([])}}ue("trails");const Un=new Set;for(let n=qt.length-1;n>=0;n--){const i=qt[n],h=i.time-f,s=ct(h),r=me(i),{a:g,open:u,x:S}=ge(i),x=an(i,S,-h),k=ln(i),J=i.mute||r?.fretHandMute,F=i.palmMute||r?.palmMute,z=Ft(i.string),W=(u?(g.width-.2)/2:.34)*(i.grace?.6:1),O=(u?.12:.42)*_*(i.grace?.6:1),lt=i.slideTo??i.slideUnpitchTo??null;if(h<-.15)continue;const nt=h<0?Math.max(0,1+h/.15):Math.min(1,(E-h)/.4);if(t.globalAlpha=nt,r&&!Un.has(i.chord)){Un.add(i.chord);const[y,T]=rt(r.notes.map(ht=>l.notes[ht].fret),i.time),C=t.globalAlpha,Z=s<Re,K=Z?.65:r.highDensity&&o.repeatMarks!=="frame"?.18:.5;if(A([[y,P,s],[T,P,s],[T,$,s],[y,$,s]]),o.frames==="gradient"){const[,ht]=v(y,P,s),[,Et]=v(y,$,s),Dt=Z?o.anchorLane:o.anchorFill;ze(di(t,`${Dt}|${K}`,[[0,I(Dt,K*.6)],[1,I(Dt,0)]]),ht,Et)}else t.globalAlpha=C*K,r.highDensity||(t.fillStyle=o.chordFill,Y()),t.strokeStyle=Z?o.anchorLane:o.chordBox,t.lineWidth=Z||!r.highDensity?1.5:1.2,tt(Z,o.anchorLane,8),N(),tt(!1);if(t.globalAlpha=C,t.strokeStyle=Lt,t.lineWidth=2,Lt&&H([y,P,s],[T,P,s]),r.highDensity&&(r.palmMute||r.fretHandMute)&&(t.strokeStyle=r.palmMute?o.muted:"#ffffff",fe((y+T)/2,P+_*.4,s,r.palmMute?.22:.12,_*(r.palmMute?.35:.22))),r.accent){const ht=Math.min(.6,(T-y)*.22),Et=($-P)*.35,Dt=Math.min(1,v(y,$,s)[2]/v(y,$,Re)[2]);t.strokeStyle="#ffffff",t.lineWidth=Math.max(1,3.5*Dt*(r.accent==="heavy"?1.4:1)),t.lineCap="square",tt(!0,"#ffffff",Math.max(2,12*Dt)),A([[y,$-Et,s],[y,$,s],[y+ht,$,s]],!1),N(),A([[T-ht,$,s],[T,$,s],[T,$-Et,s]],!1),N(),tt(!1),t.lineCap="round"}if(r.barre&&(!r.highDensity||o.repeatMarks==="grey")){const ht=r.barre.fret-.5;t.strokeStyle=r.highDensity?o.muted:"rgba(255, 255, 255, 0.7)",t.lineWidth=Math.max(3,.1*v(ht,xt/2,s)[2]);const[Et,Dt]=[st(r.barre.from),st(r.barre.to)].sort((re,Kt)=>re-Kt);H([ht,Et-_*.4,s],[ht,Dt+_*.4,s]),At(r.barre.half?"½B":"B",ht,$+.12,s,.22,r.highDensity?o.muted:o.text)}if(r.strum||r.roll){const ht=y-.25,Et=st(0)>st(U-1)?$-.1:P+.15,Dt=Et>xt/2?P+.15:$-.1,[re,Kt]=(r.strum??r.roll)==="down"?[Et,Dt]:[Dt,Et];t.strokeStyle=o.text,t.lineWidth=2,r.roll?A(Array.from({length:17},(so,Kn)=>[ht+Math.sin(Kn/16*Math.PI*6)*.06,re+(Kt-re)*Kn/16,s]),!1):A([[ht,re,s],[ht,Kt,s]],!1),N();const Ce=Kt<re?.14:-.14;H([ht-.08,Kt+Ce,s],[ht,Kt,s]),H([ht+.08,Kt+Ce,s],[ht,Kt,s])}const Pt=l.chords[i.chord-1],pe=!Pt||i.time-Pt.time>1||Pt.name!==r.name;s>Re&&r.name&&!r.highDensity&&pe&&At(r.name,y-.12,$/2,s,.34,o.text,600,"right")}const[X,at,b]=v(x,k,s);if(X<-200||X>m+200||Pn(i)){t.globalAlpha=1;continue}const St=i.repeat||r?.highDensity;if(St){const y=s<Re;t.globalAlpha*=y?.9:.4,t.strokeStyle=z,t.lineWidth=y?2:1.5,tt(y,z,8),Tt(x,k,s,W,O),N(),tt(!1),(J||F)&&o.repeatMarks!=="hide"&&Ie(x,k,s,b,u?.34:W,u?_*.3:O,F,o.muted),t.globalAlpha=nt}else{if(!u&&he){const y=i.harmonic||i.harmonicPinch?`<${i.fret}>`:i.ghost?`(${i.fret})`:String(i.fret),T=i.grace?.7:1;ee(y,x,s,ti*T,ei*T,I(z,he))}if(i.dynamicLabel&&At(i.dynamicLabel,x-.6,P,s,.3,o.text,"italic 700","right"),i.ghost&&(t.globalAlpha=nt*.5),o.gem==="pill")o.notes3d!==!1&&(Tt(x,k,s+Zn,W,O),t.fillStyle=z,Y(),t.fillStyle="rgba(255, 255, 255, 0.35)",Y()),Tt(x,k,s,W,O),t.fillStyle=z,Y();else{const y=i.harmonic||i.harmonicPinch,T=Zn;if(!y&&o.notes3d!==!1)for(const[K,Pt]of[[[[x-W,k+O,s],[x+W,k+O,s],[x+W,k+O,s+T],[x-W,k+O,s+T]],"rgba(255, 255, 255, 0.35)"],[[[x-W,k-O,s],[x-W,k+O,s],[x-W,k+O,s+T],[x-W,k-O,s+T]],"rgba(0, 0, 0, 0.4)"],[[[x+W,k-O,s],[x+W,k+O,s],[x+W,k+O,s+T],[x+W,k-O,s+T]],"rgba(0, 0, 0, 0.4)"]])A(K),t.fillStyle=z,Y(),t.fillStyle=Pt,Y();tt(s<Re,z,8),t.fillStyle=z,y?A([[x,k+O*1.3,s],[x+W*.8,k,s],[x,k-O*1.3,s],[x-W*.8,k,s]]):Tt(x,k,s,W,O),Y(),tt(!1);const[,C]=v(x,k+O,s),[,Z]=v(x,k-O,s);ze(di(t,"shine",[[0,"rgba(255, 255, 255, 0.45)"],[.5,"rgba(255, 255, 255, 0)"],[1,"rgba(0, 0, 0, 0.25)"]]),C,Z),t.strokeStyle="rgba(255, 255, 255, 0.6)",t.lineWidth=1,N()}if((J||F)&&Ie(x,k,s,b,u?.34:W,u?_*.3:O,F,u&&F?z:null),!u&&!J&&!F){const y=i.finger??(r?.fingers?.[i.string]>=0?r.fingers[i.string]:null),T=y!==null?y===0?"T":String(y):"";if(T){const C=t.globalAlpha;t.globalAlpha=C*Math.min(1,Math.max(0,(1-h/E)/.4)),At(T,x,k,s-.01,_*.62,Zt,700,"center",We,!0),t.globalAlpha=C}}}if(St&&o.repeatMarks==="hide"){t.globalAlpha=1;continue}const It=St?o.muted:o.text;if(t.globalAlpha=nt*(St?.8:1)*Math.min(1,Math.max(0,(1-h/E)/.15)),i.ghost){const[y]=v(x-W,k,s),[T]=v(x+W,k,s),C=O*b*1.5;t.strokeStyle=St?It:z,t.lineWidth=Math.max(1.2,.035*b),t.beginPath(),t.arc(y+C*.35,at,C,Math.PI*.7,Math.PI*1.3),N(),t.beginPath(),t.arc(T-C*.35,at,C,-Math.PI*.3,Math.PI*.3),N()}if(i.grace&&(t.strokeStyle=It,t.lineWidth=Math.max(1,.03*b),Xe(t,X-W*b*mt*1.2,at+O*b*1.4,X+W*b*mt*1.2,at-O*b*1.4)),i.showString){const[y]=v(x-W,k,s),T=.12*b,C=y-T-.06*b;t.strokeStyle=t.fillStyle=St?It:z,t.lineWidth=Math.max(1,.025*b),t.beginPath(),t.arc(C,at,T,0,Math.PI*2),N(),oe(String(U-i.string),C,at,.15*b,700,"center"),t.fillText(String(U-i.string),0,0),Ut()}let et=at-O*b-.18*b;t.strokeStyle=t.fillStyle=It,t.lineWidth=Math.max(1.2,.04*b),t.textAlign="center";const Dn=(y,T,C)=>{t.beginPath();for(let Z=0;Z<=20;Z++)t[Z?"lineTo":"moveTo"](X-y+2*y*Z/20,et+Math.sin(Z/20*Math.PI*2*C)*T);N()},De=(y,T,C="700")=>{T*b<2||(oe(y,X,et,T*b,C,"center"),t.fillText(y,0,0),Ut(),et-=(T+.04)*b)};let Mt=at-O*b;const G=i.tap&&!i.tapLeft;if((i.hammerOn||i.pullOff)&&!G){const y=i.grace?.6:1,T=.2*b*mt*y,C=.38*_*b*y,[Z,K]=i.hammerOn?[Mt+.4*C,Mt-.6*C]:[Mt-.6*C,Mt+.4*C];t.beginPath(),t.moveTo(X-T,K),t.lineTo(X+T,K),t.lineTo(X,Z),t.closePath(),t.fillStyle=St?It:"#ffffff",t.strokeStyle=I(o.ink,.9),t.lineWidth=Math.max(1.5,.03*b),N(),Y(),Mt-=.6*C,et=Math.min(et,Mt-.14*b),t.strokeStyle=t.fillStyle=It,t.lineWidth=Math.max(1.2,.04*b)}if(G){const y=i.grace?.6:1,T=.28*b*mt*y,C=.62*_*b*y,Z=Mt+.15*C,K=Z-C;t.beginPath(),t.moveTo(X,Z),t.lineTo(X+T,K),t.lineTo(X,K+.38*C),t.lineTo(X-T,K),t.closePath(),t.strokeStyle=I(o.ink,.9),t.lineWidth=Math.max(3.5,.1*b),N(),t.fillStyle=St?I(It,.4):I(_n(z,.55),.85),Y(),t.strokeStyle=St?It:z,t.lineWidth=Math.max(1.8,.05*b),N(),Mt=K,et=Math.min(et,Mt-.14*b),t.strokeStyle=t.fillStyle=It,t.lineWidth=Math.max(1.2,.04*b)}const q=Oe(i);if(q>0){const y=i.bendCurve?.[0]?.[1]>0,T=(i.bendCurve?.length??0)>1&&i.bendCurve.at(-1)[1]<q,C=Math.min(3,Math.max(1,Math.round(q*2))),Z=W*b*mt*.6,K=W*b*.3,Pt=K*1.25,pe=I(o.ink,.9);let ht=Mt-.04*b;const Et=Kt=>{for(let Ce=0;Ce<C;Ce++)Ai(t,X,ht-Ce*Pt-(Kt>0?0:K),Z,K,Kt,St?It:z,pe);ht-=C*Pt+.08*b},Dt=Ht(i.string);(!y||!T)&&Et(-Dt),T&&Et(Dt);const re=`${y?"pre ":""}${yi(q)}`;t.fillStyle=It,oe(re,X+Z+.08*b,(at-O*b+ht)/2,.22*b,700,"left"),t.fillText(re,0,0),Ut(),t.textAlign="center",et=Math.min(et,ht-.1*b)}i.staccato&&(t.beginPath(),t.arc(X,et+.04*b,Math.max(1.5,.045*b),0,Math.PI*2),Y(),et-=.16*b),i.accent&&(i.accent==="tenuto"||!r?.accent)&&De({heavy:"^",tenuto:"–"}[i.accent]??">",.3);const it=[i.tapLeft?"m.g.":"",bi[i.harmonicType]??(i.harmonicPinch?"PH":""),i.slap?"slap":i.pop?"pop":"",i.golpe?`golpe (${i.golpe})`:"",i.rasgueado?`rasg. ${i.rasgueado}`:"",typeof i.trill=="number"?`tr ${i.trill}`:"",i.ornament??"",i.fade??"",i.whammy?"w/bar":"",i.wah==="open"?"o":i.wah==="closed"?"+":""];for(const y of it)y&&De(y,y.length>2?.22:.28);if(i.rightFinger&&De(i.rightFinger,.26,"italic 700"),i.vibrato&&(Dn(.24*b,(i.vibratoWide?.07:.035)*b,2),et-=(.16+(i.vibratoWide?.06:0))*b),i.pick){const y=.09*b,T=.13*b;t.beginPath(),i.pick==="down"?[[-y,T/2],[-y,-T/2],[y,-T/2],[y,T/2]].forEach(([C,Z],K)=>t[K?"lineTo":"moveTo"](X+C,et+Z)):[[-y,-T/2],[0,T/2],[y,-T/2]].forEach(([C,Z],K)=>t[K?"lineTo":"moveTo"](X+C,et+Z)),N(),et-=.22*b}if(i.fermata&&(t.beginPath(),t.arc(X,et+.06*b,.14*b,Math.PI,0),N(),t.beginPath(),t.arc(X,et+.02*b,Math.max(1.5,.03*b),0,Math.PI*2),Y(),et-=.24*b),i.tremolo){for(let y=-1;y<=1;y++)Xe(t,X-.12*b,et+(y*.08+.05)*b,X+.12*b,et+(y*.08-.05)*b);et-=.3*b,Dn(.14*b,.04*b,1.5),et-=.14*b}if(lt!==null&&!u){const y=Math.sign(lt-i.fret)||1,T=X-y*.16*b,C=X+y*.16*b,Z=et+.07*b,K=et-.09*b;Xe(t,T,Z,C,K),Xe(t,C,K,C-y*.1*b,K),Xe(t,C,K,C,K+.1*b),et-=.3*b}t.globalAlpha=1}ue("notes");const Yn=new Set;for(const n of qt){const i=n.time-f,h=me(n);if(!h?.barre||Yn.has(h)||i>.06||i<-Math.max(n.sustain,.12))continue;Yn.add(h),t.strokeStyle="rgba(255, 255, 255, 0.85)",t.lineWidth=Math.max(4,.12*p);const[s,r]=[st(h.barre.from),st(h.barre.to)].sort((g,u)=>g-u);H([h.barre.fret-.5,s-_*.45,0],[h.barre.fret-.5,r+_*.45,0])}const qn=new Set,Xn=new Set;for(const n of qt){const i=n.time-f,h=me(n),s=sn.get(n.string),r=n.heldFrom??null,g=i<=.06||r!==null&&f>=r-.06,u=(n.slideTo??n.slideUnpitchTo??null)!==null;if(n.mute||i>fn||i<-Math.max(n.sustain,u?.25:.12)||(h?.highDensity||r!==null)&&!g||s&&s.note!==n&&!g||g&&qn.has(`${n.string}:${n.fret}`))continue;g&&qn.add(`${n.string}:${n.fret}`),Xn.add(`${n.string}:${n.fret}`);const{a:S,open:x,x:k}=ge(n),J=an(n,k,-i),F=ln(n),z=Ft(n.string),W=(x?(S.width-.2)/2:.32)+2/p,O=(x?.1:.36)*_+2/p;if(Tt(J,F,0,W,O),g)tt(!zn(n,i),z,14),t.fillStyle=z,Y(),tt(!1),t.strokeStyle="rgba(255, 255, 255, 0.7)",t.lineWidth=1.5,N();else{const nt=(1-i/fn)**2;t.globalAlpha=.35*nt,t.fillStyle=z,Y(),t.globalAlpha=.25+.75*nt,t.strokeStyle=z,t.lineWidth=2.2,N()}const lt=n.finger??(h?.fingers?.[n.string]>=0?h.fingers[n.string]:null);if(!x&&lt!==null&&At(lt===0?"T":String(lt),J,F,0,_*.55,g?Zt:o.text,800,"center",!g||We),!x&&Oe(n)>0){const nt=Ht(n.string),X=n.bendCurve?.[0]?.[1]>0&&n.bendCurve.at(-1)[1]<Oe(n),[at,b]=v(J,F+nt*O,0);Ai(t,at,b-nt*(X?.14:.05)*p,.17*p*mt,.085*p,(X?1:-1)*nt,"#ffffff",I(o.ink,.9))}t.globalAlpha=1}for(const n of l.handShapes??[])!n.arpeggio||n.startTime-f>fn||n.endTime<=f||(t.globalAlpha=.3+.5*Math.min(1,1-(n.startTime-f)/fn)**2,n.frets.forEach((i,h)=>{if(i<=0||h>=U||Xn.has(`${h}:${i}`))return;const s=i-.5,r=st(h),g=n.fingers[h];Tt(s,r,0,.32+2/p,.36*_+2/p),t.strokeStyle=Ft(h),t.lineWidth=2.2,N(),g>=0&&At(g===0?"T":String(g),s,r,0,_*.55,o.text,800)}),t.globalAlpha=1);ue("targets");const jn=to(l),Ln=jn.findLast(n=>n.time<=f&&f<n.end+.3),Ii=Ln?null:jn.find(n=>n.time>f&&n.time-f<1.2),Ue=Ln??Ii;if(Ue){const[n,i]=v(e.right+.4,$+.5,0),h=Jt(t,ce[700]??=`700 ${Bt}px ${o.num}`,Ue.name).width*52/Bt;t.globalAlpha=Ln?1:Math.max(.35,1-(Ue.time-f)/1.2),t.fillStyle=o.text,oe(Ue.name,Math.min(n,m-24-h),i,52,700,"left"),t.fillText(Ue.name,0,0),Ut(),t.globalAlpha=1}ue("labels")}const io=240,oo=64,xe=100,Be=24,wi=150;function ao(a,l){if(a.tabPages?.length===l)return a.tabPages.pages;const f=a.notes.at(-1),o=Math.max(f?f.time+f.sustain:0,a.beats.at(-1)?.time??0)+.5;let e=a.beats.filter(d=>d.measure>=0).map(d=>d.time);e.length<2&&(e=Array.from({length:Math.ceil(o/l)+1},(d,t)=>t*l)),e=[Math.min(0,e[0]),...e.filter(d=>d>0),Math.max(o,e.at(-1)+.01)];const M=[];let m=e[0];for(let d=1;d<e.length;d++)e[d]-m>l&&e[d-1]>m&&M.push({start:m,end:m=e[d-1]});M.push({start:m,end:e.at(-1)});for(let d=0;d<M.length-1;d++)M[d].end=M[d+1].start;return a.tabPages={length:l,pages:M},M}function fo(a,l,f,o){const{g:e,W:M}=Pi(a);if(!l)return;const m=l.strings,d=Math.min(oo,320/Math.max(1,m-1))*(o.boardHeight??1),t=Ot*.62-d*(m-1)/2,L=t+d*(m-1),R=t-d*1.65,kt=L+d*1.45,U=w=>t+(o.stringOrder==="high"?m-1-w:w)*d,wt=io*(o.noteSpeed??1),_=o.tabLayout==="pages",xt=xe+30,st=M-Be-30,Ht=_?Math.min(170,(st-xt)*.14):0,dt=st-(_?Ht+24:0);let E,j,$,P,Nt=null;if(_){const w=ao(l,(dt-xt)/wt),Q=Math.max(0,w.findLastIndex(Ct=>Ct.start<=f)),V=w[Q],bt=(dt-xt)/(V.end-V.start);E=Ct=>xt+(Ct-V.start)*bt,[$,P]=[V.start,V.end-.001],j=E(Math.min(Math.max(f,V.start),V.end)),w[Q+1]&&(Nt={start:w[Q+1].start,scale:bt})}else j=Math.max(xe+wi+60,M*.2),E=w=>j+(w-f)*wt,[$,P]=[f-(j-xe)/wt,f+(M-j)/wt];const ct=w=>o.str[w%o.str.length],Ft=w=>w.chord===null||w.chord===void 0?null:l.chords[w.chord],Lt=(w,Q,V,bt)=>{e.beginPath(),e.moveTo(w,Q),e.lineTo(V,bt),e.stroke()},he=(w,Q,V,bt)=>{const Ct=Math.hypot(V,bt),[te,zt]=[V/Ct,bt/Ct];Lt(w,Q,w-6*te-4*zt,Q-6*zt+4*te),Lt(w,Q,w-6*te+4*zt,Q-6*zt-4*te)},Vt=w=>w>=j-1?1:.4;e.lineCap="round",e.lineJoin="round",e.textBaseline="alphabetic";const vt=[],we=w=>{w&&(e.save(),e.beginPath(),e.rect(w[0],0,w[1]-w[0],Ot),e.clip());const Q=`600 ${Me(Math.min(15,d*.26))}px ${o.num}`,V=`700 ${Me(Math.min(13,d*.22))}px ${o.num}`,bt=new Map;e.font=Q,e.textAlign="left";const Ct=new Path2D,te=new Path2D;e.fillStyle=o.muted;for(let p=_e(l.beats,$-1);p<l.beats.length;p++){const c=l.beats[p];if(c.time>P)break;const D=E(c.time),gt=c.measure>=0,A=gt?Ct:te;A.moveTo(D,t-d*.35),A.lineTo(D,L+d*.35),gt&&(e.fillText(String(c.measure),D+6,R+d*.36),bt.set(Math.round(c.time*50),Jt(e,Q,String(c.measure)).width+16))}e.lineWidth=1,e.strokeStyle=I(o.text,.05),e.stroke(te),e.lineWidth=1.5,e.strokeStyle=I(o.text,.16),e.stroke(Ct),e.fillStyle=o.accent;const zt=new Map;for(const p of l.markers??[])p.time>=$&&p.time<=P&&zt.set(Math.round(p.time*50),[...zt.get(Math.round(p.time*50))??[],p.text]);for(const[p,c]of zt)e.fillText([...new Set(c)].join(" · "),E(p/50)+6+(bt.get(p)??0),R+d*.36);e.strokeStyle=I(o.text,.14),e.beginPath();for(let p=0;p<m;p++)e.moveTo(xe,U(p)),e.lineTo(M-Be,U(p));e.stroke();const ve=L+d*.92,Rt=L+d*1.24;if(o.guides!==!1){e.font=Q,e.fillStyle=e.strokeStyle=o.anchorLane,e.lineWidth=2;let p=-1/0;const c=l.anchors??[];for(let D=Math.max(1,_e(c,$));D<c.length&&c[D].time<=P;D++){const gt=c[D],A=E(gt.time);if(A<p)continue;const H=`fret ${gt.fret}`;e.globalAlpha=Vt(A),Lt(A,L+d*.6,A,ve-2),e.fillText(H,A+5,ve),p=A+5+Jt(e,Q,H).width+8}e.globalAlpha=1}e.strokeStyle=o.text,e.lineWidth=1.5;for(const p of l.hairpins??[]){if(p.endTime<$||p.time>P)continue;const c=E(p.time),D=Math.max(c+30,E(p.endTime)),[gt,A]=p.kind==="cresc"?[c,D]:[D,c];e.globalAlpha=Vt(D),e.beginPath(),e.moveTo(A,Rt-11),e.lineTo(gt,Rt-5),e.lineTo(A,Rt+1),e.stroke()}e.globalAlpha=1;const be=Me(Math.min(26,d*.42)),Gt=be*1.3,Ke=be*.32,Je=o.gem==="pill"?Gt/2:5,mt={note:`700 ${be}px ${o.num}`,grace:`700 ${Me(be*.72)}px ${o.num}`,finger:`700 ${Me(be*.5)}px ${o.num}`},Ve=o.markings==="white";for(const p of l.handShapes??[]){if(!p.arpeggio||p.endTime<$||p.startTime>P)continue;const c=p.frets.flatMap((A,H)=>A>=0&&H<m?[U(H)]:[]);if(!c.length)continue;const D=E(p.startTime)-12,gt=E(p.endTime);e.globalAlpha=Vt(gt),e.strokeStyle=I(o.text,.4),e.lineWidth=1.5,e.setLineDash([6,5]),e.beginPath(),e.roundRect(D,Math.min(...c)-Gt/2-6,gt-D,Math.max(...c)-Math.min(...c)+Gt+12,8),e.stroke(),e.setLineDash([]),p.name&&(e.font=`700 ${Me(Math.min(24,d*.4))}px ${o.num}`,e.fillStyle=o.text,e.fillText(p.name,D,t-d*.72))}e.globalAlpha=1;const Ne=p=>(p.slideTo??p.slideUnpitchTo??null)!==null||!!p.slideOut,bn=p=>{const c=Ft(p);return!!c&&!p.repeat&&!c.highDensity&&c.notes.length>1},yn=(p,c)=>4+(Ne(p)?16:0)+(bn(c)?10:0)+(c.slideIn?18:0)+(c.showString?20:0);let Ze=0,Fe=0;const ye=(p,c)=>{c(Fe-p/2),Fe-=p+3},Sn={"":V,"italic ":`italic ${V}`},Se=(p,c="")=>ye(10,D=>{e.font=Sn[c],e.fillText(p,Ze,D+5)}),{next:kn,prev:Qe,held:Tn}=hi(l),tn=new Map,en=new Set,v=[],nn=[];for(let p=_e(l.notes,$-Tn-.5);p<l.notes.length;p++){const c=l.notes[p];if(c.time>P)break;if(E(c.time+c.sustain)<xe-40-Gt*4||w&&c.time<$&&E(c.time+c.sustain)-2<=E($)&&typeof c.tieTo!="number")continue;const D=Ft(c),gt=c.grace?.72:1,A=Gt*gt,H=U(c.string),Tt=ct(c.string),rt=E(c.time),fe=c.mute||D?.fretHandMute,We=c.palmMute||D?.palmMute,Zt=c.repeat||D?.highDensity,Ie=fe?"×":c.harmonic||c.harmonicPinch?`<${c.fret}>`:c.ghost?`(${c.fret})`:String(c.fret),Qt=c.finger??(D?.fingers?.[c.string]>=0?D.fingers[c.string]:null),_t=fe||c.fret===0||Qt===null?"":Qt===0?"T":String(Qt),ke=c.grace?mt.grace:mt.note,ce=Jt(e,ke,Ie).width,oe=_t?Jt(e,mt.finger,_t).width+3:0,Ut=l.notes[kn[p]],ze=Ut?E(Ut.time)-yn(c,Ut):1/0,At=Math.min(Math.max(A,ce+oe+Ke*2*gt),Math.max(10,ze-rt)),ee=Math.max(rt+At,Math.min(E(c.time+c.sustain)-2,ze)),pt=rt+At/2,$e=Math.min(1,(At-4)/(ce+oe)),Wt=tn.get(c.string)??(Qe[p]>=0?{x0:E(l.notes[Qe[p]].time),w:Gt}:null);if(tn.set(c.string,{x0:rt,w:At}),ee<xe-40&&typeof c.tieTo!="number")continue;const Yt=c.time<=f&&f<c.time+Math.max(c.sustain,.15),tt=(Yt||rt>=j-1?1:.4)*(c.ghost?.55:1);if(e.globalAlpha=tt,D&&!en.has(D)){en.add(D);const de=D.notes.map(B=>U(l.notes[B].string)),ae=Math.min(...de)-Gt/2,N=Math.max(...de)+Gt/2,Y=rt-7;if(de.length>1&&!Zt&&(e.strokeStyle=D.accent?"#ffffff":I(o.text,.7),e.lineWidth=D.accent==="heavy"?4:D.accent?3:2,e.beginPath(),e.moveTo(Y+4,ae),e.lineTo(Y,ae),e.lineTo(Y,N),e.lineTo(Y+4,N),e.stroke()),e.font=V,e.fillStyle=e.strokeStyle=Zt?o.muted:o.text,e.lineWidth=1.8,e.textAlign="left",D.barre&&!Zt&&e.fillText(`${D.barre.half?"½":""}B${D.barre.fret}`,Y,ae-5),D.strum||D.roll){const B=D.notes.map(ie=>l.notes[ie].string),ot=U(Math.min(...B)),ft=U(Math.max(...B)),[ut,ne]=(D.strum??D.roll)==="down"?[ot,ft]:[ft,ot],Te=Y-9;e.beginPath();for(let ie=0;ie<=16;ie++)e.lineTo(Te+(D.roll?Math.sin(ie/16*Math.PI*6)*2.5:0),ut+(ne-ut)*ie/16);e.stroke(),he(Te,ne,0,ne-ut||1)}const se=l.chords[c.chord-1];D.name&&!Zt&&(!se||c.time-se.time>1||se.name!==D.name)&&(e.font=`700 ${Me(Math.min(24,d*.4))}px ${o.num}`,e.fillStyle=o.text,e.fillText(D.name,rt,t-d*.72))}e.beginPath(),e.roundRect(rt,H-A/2,ee-rt,A,Je*gt),Yt&&!Zt&&(e.shadowColor=Tt,e.shadowBlur=18),Zt?(e.strokeStyle=Tt,e.lineWidth=2,e.stroke()):c.letRing&&ee>rt+At+2?(e.fillStyle=I(Tt,.3),e.fill(),e.shadowBlur=0,e.strokeStyle=Tt,e.lineWidth=2,e.setLineDash([6,5]),Lt(rt+At+4,H,ee-4,H),e.setLineDash([]),e.beginPath(),e.roundRect(rt,H-A/2,At,A,Je*gt),e.fillStyle=Tt,e.fill()):(e.fillStyle=fe?I(o.text,.22):Tt,e.fill()),e.shadowBlur=0,Yt&&vt.push({y:H,c:Tt});const An=Zt?Tt:fe?o.text:Ve?"#ffffff":o.ink;v.push({text:Ie,font:ke,finger:_t,fill:An,shown:tt,squeeze:$e,x:pt,y:H+Jt(e,ke,Ie).middle,left:-(ce+oe)/2,textWidth:ce}),nn.push(()=>{e.globalAlpha=tt;const de=Zt?o.muted:o.text;e.strokeStyle=e.fillStyle=de,e.lineWidth=1.6;const ae=c.slideTo??c.slideUnpitchTo??null,N=ae===null?c.slideOut==="up"?1:c.slideOut?-1:0:Math.sign(ae-c.fret)||1;if(N){const B=c.slideTo===null&&c.slideUnpitchTo!==null&&c.slideUnpitchTo!==void 0;B&&e.setLineDash([3,3]),Lt(ee+4,H+N*A*.3,ee+14,H-N*A*.3),B&&e.setLineDash([])}if(c.slideIn&&Lt(rt-16,H+(c.slideIn==="below"?1:-1)*A*.3,rt-6,H-(c.slideIn==="below"?1:-1)*A*.3),typeof c.tieTo=="number"){const B=E(l.notes[c.tieTo].time)+A/2;e.setLineDash([4,3]),e.beginPath(),e.moveTo(pt,H+A/2+3),e.quadraticCurveTo((pt+B)/2,H+A/2+14,B,H+A/2+3),e.stroke(),e.setLineDash([])}if(c.showString){const B=rt-(D?26:13);e.beginPath(),e.arc(B,H,8,0,Math.PI*2),e.stroke(),e.font=mt.finger,e.textAlign="center",e.fillText(String(m-c.string),B,H+Jt(e,mt.finger,"1").middle)}c.dynamicLabel&&(e.font=`italic ${V}`,e.textAlign="left",e.fillStyle=o.text,e.fillText(c.dynamicLabel,rt,Rt),e.fillStyle=de);let Y=H-A/2-6;if(c.vibrato){e.beginPath();for(let B=rt+2;B<=Math.max(ee,rt+24)-2;B+=2)e.lineTo(B,Y+Math.sin((B-rt)/3)*(c.vibratoWide?3:1.8));e.stroke(),Y-=c.vibratoWide?10:8}if(e.textAlign="center",e.font=V,(c.hammerOn||c.pullOff)&&Wt){const B=Wt.x0+Wt.w/2,ot=(B+pt)/2;e.beginPath(),e.moveTo(B,Y),e.quadraticCurveTo(ot,Y-12,pt,Y),e.stroke(),e.fillText(c.hammerOn?"H":"P",ot,Y-9),Y-=10}const se=Oe(c);if(se>0){const B=c.bendCurve?.[0]?.[1]>0,ot=(c.bendCurve?.length??0)>1&&c.bendCurve.at(-1)[1]<se,ft=rt+At-2,ut=H-A/2,ne=ut-16;e.beginPath(),B?(e.moveTo(ft,ut),e.lineTo(ft,ne)):(e.moveTo(ft-4,ut+2),e.quadraticCurveTo(ft+4,ut,ft+6,ne)),e.stroke(),he(B?ft:ft+6,ne,B?0:.3,-1),ot&&(e.beginPath(),e.moveTo(ft+12,ne),e.quadraticCurveTo(ft+16,ut-6,ft+16,ut),e.stroke(),he(ft+16,ut,0,1)),e.textAlign="left",e.fillText(`${B?"pre ":""}${yi(se)}`,ft+(ot?20:10),ne+4),e.textAlign="center"}[Ze,Fe]=[pt,Y],c.tap&&!c.tapLeft&&Se("T"),c.staccato&&ye(4,B=>{e.beginPath(),e.arc(pt,B,2,0,Math.PI*2),e.fill()}),c.accent&&(c.accent==="tenuto"||!D?.accent)&&Se({heavy:"^",tenuto:"–"}[c.accent]??">"),We&&Se("PM");for(const B of[c.tapLeft?"m.g.":"",bi[c.harmonicType]??(c.harmonicPinch?"PH":""),c.slap?"slap":c.pop?"pop":"",c.golpe?`golpe (${c.golpe})`:"",c.rasgueado?`rasg. ${c.rasgueado}`:"",typeof c.trill=="number"?`tr ${c.trill}`:"",c.ornament??"",c.fade??"",c.whammy?"w/bar":"",c.wah==="open"?"o":c.wah==="closed"?"+":""])B&&Se(B);c.rightFinger&&Se(c.rightFinger,"italic "),c.pick&&ye(9,B=>{e.beginPath(),c.pick==="down"?[[-4,4.5],[-4,-4.5],[4,-4.5],[4,4.5]].forEach(([ot,ft],ut)=>e[ut?"lineTo":"moveTo"](pt+ot,B+ft)):[[-4,-4.5],[0,4.5],[4,-4.5]].forEach(([ot,ft],ut)=>e[ut?"lineTo":"moveTo"](pt+ot,B+ft)),e.stroke()}),c.fermata&&ye(9,B=>{e.beginPath(),e.arc(pt,B+4,7,Math.PI,0),e.stroke(),e.beginPath(),e.arc(pt,B+3,1.5,0,Math.PI*2),e.fill()}),c.tremolo&&ye(18,B=>{for(let ot=-1;ot<=1;ot++)Lt(pt-6,B+ot*4+5.5,pt+6,B+ot*4+.5);e.beginPath();for(let ot=0;ot<=12;ot++)e[ot?"lineTo":"moveTo"](pt-8+16*ot/12,B-7+Math.sin(ot/12*Math.PI*2)*2);e.stroke()})})}const on=(p,c,D,gt)=>{if(e.globalAlpha=p.shown*gt,e.fillStyle=p.fill,p.squeeze===1)return e.fillText(c,p.x+p.left+D,p.y);e.save(),e.translate(p.x,p.y),e.scale(p.squeeze,1),e.fillText(c,p.left+D,0),e.restore()};e.textAlign="left";for(const p of[mt.note,mt.grace]){e.font=p;for(const c of v)c.font===p&&on(c,c.text,0,1)}e.font=mt.finger;for(const p of v)p.finger&&on(p,p.finger,p.textWidth+3,.7);for(const p of nn)p();e.globalAlpha=1,w&&e.restore()};if(!_)we(null);else if(we([xt-40,dt+4]),Nt){const w=dt+24,Q=j;E=V=>w+(V-Nt.start)*Nt.scale,[$,P,j]=[Nt.start,Nt.start+Ht/Nt.scale,-1/0],we([w-8,st+4]),e.save(),e.globalCompositeOperation="destination-out",e.fillStyle="rgba(0, 0, 0, 0.55)",e.fillRect(w-8,0,st+12-(w-8),Ot),e.restore(),e.strokeStyle=I(o.text,.22),e.lineWidth=1.5,e.setLineDash([3,5]),Lt(dt+12,t-d*.6,dt+12,L+d*.6),e.setLineDash([]),j=Q}e.shadowColor=o.accent,e.shadowBlur=16,e.strokeStyle=o.accent,e.lineWidth=3,Lt(j,t-d*.7,j,L+d*.7);for(const{y:w,c:Q}of vt)e.shadowColor=Q,e.fillStyle="#ffffff",e.beginPath(),e.arc(j,w,4,0,Math.PI*2),e.fill();e.shadowBlur=0,e.globalCompositeOperation="destination-out";for(const[w,Q,V]of _?[]:[[xe+10,1,wi],[M-Be,-1,80]]){const bt=e.createLinearGradient(w,0,w+Q*V,0);bt.addColorStop(0,"rgba(0, 0, 0, 1)"),bt.addColorStop(1,"rgba(0, 0, 0, 0)"),e.fillStyle=bt,e.fillRect(Q>0?0:w-V,0,Q>0?w+V:M-w+V,Ot)}e.globalCompositeOperation="destination-over",e.beginPath(),e.roundRect(Be,R,M-Be*2,kt-R,16),e.fillStyle=I(o.ink,.72),e.fill(),e.globalCompositeOperation="source-over",e.strokeStyle=o.chipBorder,e.lineWidth=1,e.stroke();const He=`700 ${Me(Math.min(14,d*.24))}px ${o.num}`,je=Math.min(13,d*.22);e.font=He,e.textAlign="center";for(let w=0;w<m&&l.open;w++){const Q=(Be+xe)/2,V=U(w);e.strokeStyle=e.fillStyle=ct(w),e.lineWidth=1.8,e.beginPath(),e.arc(Q,V,je,0,Math.PI*2),e.stroke(),e.fillText($i(l.open[w]),Q,V+Jt(e,He,"E").middle)}}export{Ui as HEADSTOCKS,Zi as bendAt,ho as drawHighway,fo as drawTab,Yi as headstockParts,Ri as lookAhead,no as moveCamera,ai as rounded,ri as spline};
package/index.html CHANGED
@@ -11,7 +11,7 @@ rel="preload"
11
11
  href="https://cdn.jsdelivr.net/npm/@coderline/alphatab@1.8.4/dist/alphaTab.min.js"
12
12
  as="script"
13
13
  />
14
- <style>:root{--bg: #0e1014;--ink: #0e1014;--text: #e8eaef;--muted: #7b8190;--accent: #c8f04a;--chip: #171a20;--chip-border: #2a2f38;--done: #e8eaef;--todo: #23272f;--ui: system-ui, sans-serif;--num: system-ui, sans-serif;--lyric: system-ui, sans-serif;--lyric-style: normal}*{box-sizing:border-box}[hidden]{display:none!important}html,body{height:100%}body{margin:0;overflow:hidden;background:var(--bg);color:var(--text);font:14px/1.4 var(--ui);accent-color:var(--accent)}canvas{position:fixed;inset:0;width:100%;height:100%;display:block}button{font:inherit;color:inherit}.bar{position:fixed;z-index:3;left:32px;right:32px;top:18px;height:40px;display:flex;align-items:center;justify-content:space-between;gap:24px;transition:transform .25s ease,opacity .25s ease,visibility .25s}.group{display:flex;align-items:center;gap:10px;min-width:0}.group:last-child{flex:none}.wordmark{display:flex;align-items:center;gap:7px;font:700 15px var(--num);letter-spacing:.22em}:is(.wordmark,.welcome-mark) .fall{transform-box:fill-box;transform-origin:center;transform:rotate(14deg);animation:fall .75s .8s both}@keyframes fall{0%{transform:translate(-3.5px,-1.42px) rotate(0);animation-timing-function:cubic-bezier(.55,0,.85,.35)}40%{transform:translate(0) rotate(18deg);animation-timing-function:cubic-bezier(.2,.7,.4,1)}56%{transform:translateY(-.35px) rotate(11.5deg);animation-timing-function:ease-in-out}74%{transform:translateY(.08px) rotate(15.2deg);animation-timing-function:ease-in-out}88%{transform:translate(0) rotate(13.6deg);animation-timing-function:ease-in-out}to{transform:translate(0) rotate(14deg)}}@media(prefers-reduced-motion:reduce){.wordmark .fall{animation:none}}.seg{display:flex;gap:2px;padding:3px;border-radius:9px;background:var(--chip);border:1px solid var(--chip-border);overflow-x:auto;scrollbar-width:none}.seg button{border:0;background:none;cursor:pointer;padding:5px 12px;border-radius:6px;font:500 13px var(--ui);color:var(--muted);white-space:nowrap}.seg button[aria-pressed=true]{background:var(--text);color:var(--ink);font-weight:600}.seg select{max-width:22vw;border:0;padding:4px 6px;background:none;color:var(--text);font:600 13px var(--ui)}.seg option{background:var(--ink);color:var(--text)}.icon{flex:none;cursor:pointer;width:36px;height:36px;display:grid;place-items:center;padding:0;border-radius:8px;background:var(--chip);border:1px solid var(--chip-border);color:var(--text)}.icon[aria-pressed=true],.icon[aria-expanded=true]{background:var(--accent);border-color:var(--accent);color:var(--ink)}button:focus-visible,input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.speed{height:36px;display:flex;align-items:center;padding:0 2px;border-radius:8px;background:var(--chip);border:1px solid var(--chip-border);color:var(--muted)}.speed button{cursor:pointer;width:28px;height:32px;display:grid;place-items:center;padding:0;border:0;background:none;color:inherit}.speed #speed{width:auto;min-width:46px;font:600 14px var(--num);color:var(--text)}.time{margin-right:6px;font:14px var(--num);color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}.divider{width:1px;height:24px;margin:0 4px;background:var(--chip-border)}.menu{display:contents}#menuButton{display:none}#phrases{position:fixed;left:32px;right:32px;top:74px;height:54px;cursor:pointer;touch-action:none;-webkit-user-select:none;user-select:none}#phrases div{position:absolute;bottom:0;min-width:2px;border-radius:2px;background:var(--todo)}#phrases div.done{background:var(--done)}#phraseTime{position:absolute;top:calc(100% + 16px);transform:translate(-50%);padding:2px 7px;border-radius:6px;background:var(--ink);border:1px solid var(--chip-border);font:600 11px var(--num);font-variant-numeric:tabular-nums;color:var(--text);pointer-events:none}#loopBox{position:absolute;top:-6px;bottom:-17px;border:1.5px solid var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent);box-shadow:0 0 18px color-mix(in srgb,var(--accent) 22%,transparent)}#loopBox:before,#loopBox:after{content:"";position:absolute;top:-11px;bottom:-11px;width:4px;border:4px solid transparent;border-radius:6px;background:var(--accent) padding-box;cursor:ew-resize}#loopBox:before{left:-6.75px}#loopBox:after{right:-6.75px}#progress{position:fixed;left:32px;right:32px;top:134px;height:5px;border-radius:3px;overflow:hidden;background:var(--todo)}#progress div{width:0;height:100%;background:var(--accent);opacity:.9}#lyrics{position:fixed;left:40px;top:164px;max-width:min(560px,46vw);display:flex;flex-direction:column;gap:8px;pointer-events:none;font-family:var(--lyric);font-style:var(--lyric-style);text-shadow:0 2px 14px var(--ink),0 0 4px var(--ink)}#section{min-height:16px;font:600 12px var(--num);letter-spacing:.18em;color:var(--accent)}#lines{position:relative;height:2.45em;font-size:clamp(20px,2.3vw,32px);line-height:1.15}#lines div{position:absolute;top:0;left:0;white-space:nowrap;color:var(--muted);transition:transform .45s cubic-bezier(.22,1,.36,1),opacity .35s ease}#lines .low{transform:translateY(1.3em);opacity:.5}#lines .gone{opacity:0;transition-duration:.45s,.25s}#lines .gone.up{transform:translateY(-.8em)}#lines span{transition:color .15s}#lines .sung{color:var(--text)}@media(prefers-reduced-motion:reduce){#lines div{transition-property:opacity}}#info{position:fixed;left:40px;right:226px;bottom:14px;display:flex;align-items:center;font-size:13px;white-space:nowrap;color:var(--muted);pointer-events:none}#info b{color:var(--text);font-weight:600}#info>span+span:before{content:"";display:inline-block;width:1px;height:12px;margin:0 14px;vertical-align:-1px;background:var(--chip-border)}#info .tuning{position:relative;pointer-events:auto;cursor:help}#info .tuning>b{text-decoration:underline dotted var(--muted);text-underline-offset:3px}#info .tip{left:0;right:auto;white-space:normal}#info .tuning:is(:hover,:focus)>.tip{opacity:1;visibility:visible;transform:none}.pegs{display:flex;align-items:flex-start;gap:4px;margin:10px 0 8px}.peg{display:flex;flex-direction:column;align-items:center;min-width:26px;gap:2px;font:600 13px var(--num)}.peg i{font-style:normal;font-size:11px;color:var(--muted)}.peg .move:before{content:"";display:block;width:3px;height:calc(6px + var(--d) * 3px);margin:2px auto 3px;border-radius:2px;background:var(--c)}.peg strong{color:var(--c)}.peg.same{opacity:.45}.tip small{display:block;font-size:11px}:root:fullscreen .bar{transform:translateY(calc(-100% - 18px));opacity:0;visibility:hidden;transition-delay:.4s}:root:fullscreen:has(#phrases:hover,#progress:hover,.bar:hover) .bar{transform:none;opacity:1;visibility:visible;transition-delay:0s}#tools{position:fixed;z-index:3;right:32px;bottom:6px}#tools .icon{position:relative}.icon:disabled{cursor:default;color:var(--muted)}.icon:disabled svg{opacity:.5}#loopTools{position:fixed;z-index:4;display:flex;transform:translate(-50%,calc(-50% + 3px))}#loopTools .icon{width:32px;height:26px;background:var(--ink);border-color:var(--accent)}#loopTools svg{width:15px;height:15px}#trainer{border-radius:13px 0 0 13px}#clearLoop{border-left:0;border-radius:0 13px 13px 0;color:var(--muted)}#clearLoop:hover{color:var(--text)}#loopTools .icon[aria-pressed=true]{background:var(--accent);color:var(--ink)}.tip{position:absolute;right:0;bottom:calc(100% + 10px);width:max-content;max-width:250px;padding:8px 10px;border-radius:8px;background:var(--ink);border:1px solid var(--chip-border);box-shadow:0 12px 30px #00000073;color:var(--muted);font:12px/1.45 var(--ui);text-align:left;pointer-events:none;opacity:0;visibility:hidden;transform:translateY(4px);transition:opacity .12s ease,transform .12s ease,visibility .12s}.tip b{display:flex;justify-content:space-between;gap:12px;margin-bottom:2px;color:var(--text);font-weight:600}.tip kbd{padding:0 5px;border:1px solid var(--chip-border);border-radius:4px;color:var(--muted);font:inherit}:is(.icon,.speed):hover>.tip,.icon:focus-visible>.tip,.speed:focus-within>.tip{opacity:1;visibility:visible;transform:none}.bar :is(.icon,.speed){position:relative}.bar .tip{top:calc(100% + 10px);bottom:auto;transform:translateY(-4px)}.bar [aria-expanded=true]>.tip{display:none}#loopTools .tip{top:calc(100% + 10px);bottom:auto;left:var(--tip, 50%);right:auto;transform:translate(calc(-1 * var(--tip, 50%)),-4px)}#loopTools .icon:hover>.tip,#loopTools .icon:focus-visible>.tip{transform:translate(calc(-1 * var(--tip, 50%)))}:root:fullscreen :is(#info,#tools>:not(#minimal)){display:none}:root.minimal :is(.bar,#phrases,#progress,#loopTools,#info,#tools>:not(#minimal)){display:none}:root.tab2d .only-3d,:root:not(.tab2d) .only-2d{display:none}:root.tab2d .only-3d+.only-3d+h3{padding-top:0;border-top:0}:root.minimal #lyrics{top:24px}#status{position:fixed;left:50%;top:42%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:12px;max-width:min(560px,90vw);padding:10px 16px;border-radius:10px;background:var(--chip);border:1px solid var(--chip-border);backdrop-filter:blur(10px);text-align:center}:root.banding :is(#highway,#phrases,#progress,#loopTools,#lyrics,#info,#intro,#time){display:none}#bandNote{position:fixed;left:50%;top:56%;transform:translate(-50%,-50%);display:grid;justify-items:center;gap:8px;max-width:min(440px,90vw);padding:14px 20px;border-radius:10px;background:var(--chip);border:1px solid var(--chip-border);text-align:center}#bandNote .text-button{justify-self:center}#status:not(.loading) .bars{display:none}.bars{flex:none;display:inline-flex;align-items:flex-end;gap:3px;height:16px}.bars i{width:3px;height:100%;border-radius:2px;background:var(--accent);transform:scaleY(.3);transform-origin:bottom}.bars.moving i{animation:bars .8s ease-in-out infinite alternate}.bars.moving i:nth-child(2){animation-duration:1.1s;animation-delay:-.5s}.bars.moving i:nth-child(3){animation-duration:.7s;animation-delay:-.2s}.bars.moving i:nth-child(4){animation-duration:1s;animation-delay:-.7s}@keyframes bars{0%{transform:scaleY(.2)}to{transform:scaleY(1)}}@media(prefers-reduced-motion:reduce){.bars.moving i{animation:none;transform:scaleY(.6)}}#intro{position:fixed;left:50%;top:36%;transform:translate(-50%,-50%);display:grid;justify-items:center;gap:6px;max-width:min(640px,90vw);padding:22px 30px;border-radius:16px;background:color-mix(in srgb,var(--ink) 72%,transparent);border:1px solid var(--chip-border);text-align:center;pointer-events:none;opacity:0;visibility:hidden;transition:opacity .5s ease,visibility .5s}#intro.show{opacity:1;visibility:visible}#introTitle{font:700 clamp(22px,3vw,38px) / 1.15 var(--num);color:var(--text)}#introFacts{font-size:14px;color:var(--muted)}#introState{display:flex;align-items:center;gap:10px;margin-top:10px;font:600 12px var(--num);letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}.sheet{position:fixed;right:32px;top:66px;z-index:2;width:min(400px,calc(100vw - 32px));max-height:calc(100vh - 118px);display:flex;flex-direction:column;border-radius:14px;overflow:hidden;background:color-mix(in srgb,var(--ink) 94%,transparent);backdrop-filter:blur(18px);border:1px solid var(--chip-border);box-shadow:0 24px 60px #0000008c}.sheet-head{display:flex;align-items:center;justify-content:space-between;padding:12px 12px 10px 18px}.sheet-head h2{margin:0;font:600 15px var(--ui)}.close{width:30px;height:30px;display:grid;place-items:center;padding:0;border:0;border-radius:8px;background:none;color:var(--muted);cursor:pointer}.close:hover{background:var(--chip);color:var(--text)}.tabs{display:grid;grid-template-columns:repeat(5,1fr);gap:2px;margin:0 14px;padding:3px;border-radius:9px;background:var(--chip);border:1px solid var(--chip-border)}.tabs button{padding:6px 0;border:0;border-radius:6px;background:none;font:500 13px var(--ui);color:var(--muted);cursor:pointer}.tabs button:hover{color:var(--text)}.tabs button[aria-selected=true]{background:var(--text);color:var(--ink);font-weight:600}.pane{display:grid;align-content:start;gap:18px;padding:18px 18px 20px;overflow:hidden auto}.pane h3{margin:0 0 -6px;font:600 11px var(--num);letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}.pane h3~h3{padding-top:16px;border-top:1px solid var(--chip-border)}.setting{display:grid;gap:8px}.pair{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:18px 20px}.setting-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;font-size:13px;font-weight:500}.setting-head output{font:600 12px var(--num);color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}.setting .seg{overflow:visible}.setting .seg button{flex:1}.scale{display:flex;justify-content:space-between;margin-top:-4px;font-size:11px;color:var(--muted)}.hint{margin:-2px 0 0;font-size:12px;line-height:1.4;color:var(--muted)}.text-button{justify-self:start;padding:4px 0;border:0;background:none;font:500 12px var(--ui);color:var(--muted);text-decoration:underline;text-underline-offset:3px;cursor:pointer}.text-button:hover{color:var(--text)}:is(#settings,.volume) input[type=range]{-webkit-appearance:none;appearance:none;height:18px;margin:0;background:none;cursor:pointer}#settings input[type=range]{width:100%}:is(#settings,.volume) input[type=range]::-webkit-slider-runnable-track{height:4px;border-radius:2px;background:linear-gradient(90deg,var(--accent) var(--fill, 50%),var(--chip-border) var(--fill, 50%))}:is(#settings,.volume) input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:16px;height:16px;margin-top:-6px;border-radius:50%;background:var(--text);border:3px solid var(--accent);box-shadow:0 1px 4px #0006}:is(#settings,.volume) input[type=range]::-moz-range-track{height:4px;border-radius:2px;background:var(--chip-border)}:is(#settings,.volume) input[type=range]::-moz-range-progress{height:4px;border-radius:2px;background:var(--accent)}:is(#settings,.volume) input[type=range]::-moz-range-thumb{width:10px;height:10px;border-radius:50%;background:var(--text);border:3px solid var(--accent)}.toggle{display:flex;align-items:center;justify-content:space-between;gap:16px;font-size:13px;font-weight:500;cursor:pointer}.toggle small{display:block;margin-top:2px;font-size:12px;font-weight:400;line-height:1.4;color:var(--muted)}.toggle input{-webkit-appearance:none;appearance:none;flex:none;position:relative;width:36px;height:20px;margin:0;border-radius:10px;background:var(--chip-border);cursor:pointer;transition:background .15s}.toggle input:after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--text);transition:transform .15s}.toggle input:checked{background:var(--accent)}.toggle input:checked:after{transform:translate(16px);background:var(--ink)}.cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}.cards.three{grid-template-columns:repeat(3,minmax(0,1fr))}.cards button{display:grid;gap:8px;justify-items:start;padding:10px;border-radius:9px;border:1px solid var(--chip-border);background:var(--chip);font:500 12px var(--ui);color:var(--muted);text-align:left;cursor:pointer}.cards button:hover{color:var(--text)}.cards button[aria-pressed=true]{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent);color:var(--text)}.dots{display:flex;gap:4px}.dots i{width:10px;height:10px;border-radius:50%;box-shadow:inset 0 0 0 1px #ffffff2e}.headstock{width:100%;height:52px}.order{font:600 12px var(--num);letter-spacing:.12em;color:var(--text)}#legend{width:min(430px,calc(100vw - 32px))}.legend-find{padding:0 14px 6px}.legend-find input{width:100%;height:34px;padding:0 12px;border-radius:9px;border:1px solid var(--chip-border);background:var(--chip);color:var(--text);font:13px var(--ui)}.legend-find input::placeholder{color:var(--muted)}.legend{gap:4px;padding-top:10px}.legend h3{margin:14px 0 4px}.legend h3:first-child{margin-top:0}.legend-item{display:grid;grid-template-columns:64px 1fr;gap:12px;align-items:center;padding:4px 0}.legend-item b{display:block;font-size:13px;font-weight:500}.legend-item span{display:block;font-size:12px;line-height:1.4;color:var(--muted)}.legend-item .keys{display:flex;justify-content:center;gap:4px}.legend-item kbd{min-width:22px;padding:2px 6px;border:1px solid var(--chip-border);border-bottom-width:2px;border-radius:5px;background:var(--chip);font:600 12px var(--num);text-align:center;white-space:nowrap}.legend-item svg{width:64px;height:36px;border-radius:8px;background:var(--chip);border:1px solid var(--chip-border);fill:none;stroke-linecap:round;stroke-linejoin:round}.legend-item text{font-family:var(--num);font-weight:700;text-anchor:middle;dominant-baseline:central}.legend-empty{margin:8px 0;font-size:13px;color:var(--muted)}.f0{fill:var(--s0)}.f1{fill:var(--s1)}.f2{fill:var(--s2)}.f3{fill:var(--s3)}.f4{fill:var(--s4)}.l0{stroke:var(--s0)}.l1{stroke:var(--s1)}.l2{stroke:var(--s2)}.l3{stroke:var(--s3)}.l4{stroke:var(--s4)}.lm{stroke:var(--muted)}.li{stroke:var(--ink)}.ft{fill:var(--text)}.lt{stroke:var(--text)}.fi{fill:var(--ink)}.fa{fill:var(--accent)}.fl{fill:var(--lane)}.ll{stroke:var(--lane)}.lw{stroke:#fff}.fm{fill:var(--muted)}.la{stroke:var(--accent)}.fw{fill:#fff}.volume{position:relative}.volume .icon.muted{color:var(--muted)}.volume-panel{position:absolute;top:calc(100% + 8px);left:50%;transform:translate(-50%);display:flex;align-items:center;gap:8px;padding:6px 14px 6px 6px;border-radius:10px;background:var(--ink);border:1px solid var(--chip-border);box-shadow:0 12px 30px #00000073}.volume-panel input{width:150px}.volume-panel output{min-width:36px;font:600 12px var(--num);color:var(--muted);text-align:right;font-variant-numeric:tabular-nums}.volume-mute{flex:none;width:30px;height:30px;display:grid;place-items:center;padding:0;border:0;border-radius:7px;background:none;color:var(--text);cursor:pointer}.volume-mute:hover{background:var(--chip)}.volume-mute[aria-pressed=true]{color:var(--muted)}#drop{position:fixed;inset:12px;z-index:5;display:grid;place-items:center;border:2px dashed var(--accent);border-radius:16px;background:#00000073;font:600 20px var(--num)}#tab{position:fixed;left:-10000px;top:0;width:1000px}@media(max-width:900px){.time{display:none}#menuButton{display:grid}.volume{position:static}.volume-panel{left:auto;right:0;transform:none}.menu{display:none;position:absolute;top:calc(100% + 8px);right:0;width:230px;flex-direction:column;gap:2px;padding:6px;border-radius:12px;background:var(--ink);border:1px solid var(--chip-border);box-shadow:0 12px 30px #00000073}#menuButton[aria-expanded=true]+.menu{display:flex}.menu .icon{width:100%;height:38px;display:flex;justify-content:flex-start;gap:12px;padding:0 10px;border:0;border-radius:7px;background:none;font:500 13px var(--ui)}.menu .icon:after{content:attr(data-label)}.menu .icon:hover{background:var(--chip)}.menu .icon[aria-pressed=true],.menu .icon[aria-expanded=true]{background:none;color:var(--accent)}.menu .tip{display:none}.menu .divider{width:auto;height:1px;margin:4px}}@media(max-width:560px){.bar{flex-wrap:wrap;height:auto;row-gap:8px}.bar>.group:first-child,.bar>.group:last-child{flex:1 1 100%;height:40px}.speed{margin-left:auto}#menuButton{position:absolute;top:2px;right:0}.menu{top:48px}#phrases{top:122px}#info{flex-direction:column;align-items:flex-start;gap:2px;font-size:12px}#info>span+span:before{display:none}#info>span:first-child{max-width:100%;overflow:hidden;text-overflow:ellipsis}#progress{top:182px}#lyrics{top:212px}.sheet{top:114px;max-height:calc(100vh - 166px)}}@media(max-width:520px){.sheet{right:16px}}</style>
14
+ <style>:root{--bg: #0e1014;--ink: #0e1014;--text: #e8eaef;--muted: #7b8190;--accent: #c8f04a;--chip: #171a20;--chip-border: #2a2f38;--done: #e8eaef;--todo: #23272f;--ui: system-ui, sans-serif;--num: system-ui, sans-serif;--lyric: system-ui, sans-serif;--lyric-style: normal}*{box-sizing:border-box}[hidden]{display:none!important}html,body{height:100%}body{margin:0;overflow:hidden;background:var(--bg);color:var(--text);font:14px/1.4 var(--ui);accent-color:var(--accent)}canvas{position:fixed;inset:0;width:100%;height:100%;display:block}button{font:inherit;color:inherit}.bar{position:fixed;z-index:3;left:32px;right:32px;top:18px;height:40px;display:flex;align-items:center;justify-content:space-between;gap:24px;transition:transform .25s ease,opacity .25s ease,visibility .25s}.group{display:flex;align-items:center;gap:10px;min-width:0}.group:last-child{flex:none}.wordmark{display:flex;align-items:center;gap:7px;font:700 15px var(--num);letter-spacing:.22em}:is(.wordmark,.welcome-mark) .fall{transform-box:fill-box;transform-origin:center;transform:rotate(14deg);animation:fall .75s .8s both}@keyframes fall{0%{transform:translate(-3.5px,-1.42px) rotate(0);animation-timing-function:cubic-bezier(.55,0,.85,.35)}40%{transform:translate(0) rotate(18deg);animation-timing-function:cubic-bezier(.2,.7,.4,1)}56%{transform:translateY(-.35px) rotate(11.5deg);animation-timing-function:ease-in-out}74%{transform:translateY(.08px) rotate(15.2deg);animation-timing-function:ease-in-out}88%{transform:translate(0) rotate(13.6deg);animation-timing-function:ease-in-out}to{transform:translate(0) rotate(14deg)}}@media(prefers-reduced-motion:reduce){.wordmark .fall{animation:none}}.seg{display:flex;gap:2px;padding:3px;border-radius:9px;background:var(--chip);border:1px solid var(--chip-border);overflow-x:auto;scrollbar-width:none}.seg button{border:0;background:none;cursor:pointer;padding:5px 12px;border-radius:6px;font:500 13px var(--ui);color:var(--muted);white-space:nowrap}.seg button[aria-pressed=true]{background:var(--text);color:var(--ink);font-weight:600}.seg select{max-width:22vw;border:0;padding:4px 6px;background:none;color:var(--text);font:600 13px var(--ui)}.seg option{background:var(--ink);color:var(--text)}.icon{flex:none;cursor:pointer;width:36px;height:36px;display:grid;place-items:center;padding:0;border-radius:8px;background:var(--chip);border:1px solid var(--chip-border);color:var(--text)}.icon[aria-pressed=true],.icon[aria-expanded=true]{background:var(--accent);border-color:var(--accent);color:var(--ink)}button:focus-visible,input:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.speed{height:36px;display:flex;align-items:center;padding:0 2px;border-radius:8px;background:var(--chip);border:1px solid var(--chip-border);color:var(--muted)}.speed button{cursor:pointer;width:28px;height:32px;display:grid;place-items:center;padding:0;border:0;background:none;color:inherit}.speed #speed{width:auto;min-width:46px;font:600 14px var(--num);color:var(--text)}.time{margin-right:6px;font:14px var(--num);color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}.divider{width:1px;height:24px;margin:0 4px;background:var(--chip-border)}.menu{display:contents}#menuButton{display:none}#phrases{position:fixed;left:32px;right:32px;top:74px;height:54px;cursor:pointer;touch-action:none;-webkit-user-select:none;user-select:none}#phrases div{position:absolute;bottom:0;min-width:2px;border-radius:2px;background:var(--todo)}#phrases div.done{background:var(--done)}#phraseTime{position:absolute;top:calc(100% + 16px);transform:translate(-50%);padding:2px 7px;border-radius:6px;background:var(--ink);border:1px solid var(--chip-border);font:600 11px var(--num);font-variant-numeric:tabular-nums;color:var(--text);pointer-events:none}#loopBox{position:absolute;top:-6px;bottom:-17px;border:1.5px solid var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent);box-shadow:0 0 18px color-mix(in srgb,var(--accent) 22%,transparent)}#loopBox:before,#loopBox:after{content:"";position:absolute;top:-11px;bottom:-11px;width:4px;border:4px solid transparent;border-radius:6px;background:var(--accent) padding-box;cursor:ew-resize}#loopBox:before{left:-6.75px}#loopBox:after{right:-6.75px}#progress{position:fixed;left:32px;right:32px;top:134px;height:5px;border-radius:3px;overflow:hidden;background:var(--todo)}#progress div{width:0;height:100%;background:var(--accent);opacity:.9}:root[data-docked] #phrases{top:18px}:root[data-docked] #progress{top:78px}:root[data-docked] #lyrics{top:108px}:root[data-docked] .sheet{top:18px}#lyrics{position:fixed;left:40px;top:164px;max-width:min(560px,46vw);display:flex;flex-direction:column;gap:8px;pointer-events:none;font-family:var(--lyric);font-style:var(--lyric-style);text-shadow:0 2px 14px var(--ink),0 0 4px var(--ink)}#section{min-height:16px;font:600 12px var(--num);letter-spacing:.18em;color:var(--accent)}#lines{position:relative;height:2.45em;font-size:clamp(20px,2.3vw,32px);line-height:1.15}#lines div{position:absolute;top:0;left:0;white-space:nowrap;color:var(--muted);transition:transform .45s cubic-bezier(.22,1,.36,1),opacity .35s ease}#lines .low{transform:translateY(1.3em);opacity:.5}#lines .gone{opacity:0;transition-duration:.45s,.25s}#lines .gone.up{transform:translateY(-.8em)}#lines span{transition:color .15s}#lines .sung{color:var(--text)}@media(prefers-reduced-motion:reduce){#lines div{transition-property:opacity}}#info{position:fixed;left:40px;right:226px;bottom:14px;display:flex;align-items:center;font-size:13px;white-space:nowrap;color:var(--muted);pointer-events:none}#info b{color:var(--text);font-weight:600}#info>span+span:before{content:"";display:inline-block;width:1px;height:12px;margin:0 14px;vertical-align:-1px;background:var(--chip-border)}#info .tuning{position:relative;pointer-events:auto;cursor:help}#info .tuning>b{text-decoration:underline dotted var(--muted);text-underline-offset:3px}#info .tip{left:0;right:auto;white-space:normal}#info .tuning:is(:hover,:focus)>.tip{opacity:1;visibility:visible;transform:none}.pegs{display:flex;align-items:flex-start;gap:4px;margin:10px 0 8px}.peg{display:flex;flex-direction:column;align-items:center;min-width:26px;gap:2px;font:600 13px var(--num)}.peg i{font-style:normal;font-size:11px;color:var(--muted)}.peg .move:before{content:"";display:block;width:3px;height:calc(6px + var(--d) * 3px);margin:2px auto 3px;border-radius:2px;background:var(--c)}.peg strong{color:var(--c)}.peg.same{opacity:.45}.tip small{display:block;font-size:11px}:root:fullscreen .bar{transform:translateY(calc(-100% - 18px));opacity:0;visibility:hidden;transition-delay:.4s}:root:fullscreen:has(#phrases:hover,#progress:hover,.bar:hover) .bar{transform:none;opacity:1;visibility:visible;transition-delay:0s}#tools{position:fixed;z-index:3;right:32px;bottom:6px}#tools .icon{position:relative}.icon:disabled{cursor:default;color:var(--muted)}.icon:disabled svg{opacity:.5}#loopTools{position:fixed;z-index:4;display:flex;transform:translate(-50%,calc(-50% + 3px))}#loopTools .icon{width:32px;height:26px;background:var(--ink);border-color:var(--accent)}#loopTools svg{width:15px;height:15px}#trainer{border-radius:13px 0 0 13px}#clearLoop{border-left:0;border-radius:0 13px 13px 0;color:var(--muted)}#clearLoop:hover{color:var(--text)}#loopTools .icon[aria-pressed=true]{background:var(--accent);color:var(--ink)}.tip{position:absolute;right:0;bottom:calc(100% + 10px);width:max-content;max-width:250px;padding:8px 10px;border-radius:8px;background:var(--ink);border:1px solid var(--chip-border);box-shadow:0 12px 30px #00000073;color:var(--muted);font:12px/1.45 var(--ui);text-align:left;pointer-events:none;opacity:0;visibility:hidden;transform:translateY(4px);transition:opacity .12s ease,transform .12s ease,visibility .12s}.tip b{display:flex;justify-content:space-between;gap:12px;margin-bottom:2px;color:var(--text);font-weight:600}.tip kbd{padding:0 5px;border:1px solid var(--chip-border);border-radius:4px;color:var(--muted);font:inherit}:is(.icon,.speed):hover>.tip,.icon:focus-visible>.tip,.speed:focus-within>.tip{opacity:1;visibility:visible;transform:none}:root:where([data-fretfall-dock]){display:flex;align-items:center;gap:10px}.bar :is(.icon,.speed),:root:where([data-fretfall-dock]) :is(.icon,.speed){position:relative}.bar .tip,:root:where([data-fretfall-dock]) .tip{top:calc(100% + 10px);bottom:auto;transform:translateY(-4px)}.bar [aria-expanded=true]>.tip,:root:where([data-fretfall-dock]) [aria-expanded=true]>.tip{display:none}#loopTools .tip{top:calc(100% + 10px);bottom:auto;left:var(--tip, 50%);right:auto;transform:translate(calc(-1 * var(--tip, 50%)),-4px)}#loopTools .icon:hover>.tip,#loopTools .icon:focus-visible>.tip{transform:translate(calc(-1 * var(--tip, 50%)))}:root:fullscreen :is(#info,#tools>:not(#minimal)){display:none}:root.minimal :is(.bar,#phrases,#progress,#loopTools,#info,#tools>:not(#minimal)){display:none}:root.tab2d .only-3d,:root:not(.tab2d) .only-2d{display:none}:root.tab2d .only-3d+.only-3d+h3{padding-top:0;border-top:0}:root.minimal #lyrics{top:24px}#status{position:fixed;left:50%;top:42%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:12px;max-width:min(560px,90vw);padding:10px 16px;border-radius:10px;background:var(--chip);border:1px solid var(--chip-border);backdrop-filter:blur(10px);text-align:center}:root.banding :is(#highway,#phrases,#progress,#loopTools,#lyrics,#info,#intro,#time){display:none}#bandNote{position:fixed;left:50%;top:56%;transform:translate(-50%,-50%);display:grid;justify-items:center;gap:8px;max-width:min(440px,90vw);padding:14px 20px;border-radius:10px;background:var(--chip);border:1px solid var(--chip-border);text-align:center}#bandNote .text-button{justify-self:center}#status:not(.loading) .bars{display:none}.bars{flex:none;display:inline-flex;align-items:flex-end;gap:3px;height:16px}.bars i{width:3px;height:100%;border-radius:2px;background:var(--accent);transform:scaleY(.3);transform-origin:bottom}.bars.moving i{animation:bars .8s ease-in-out infinite alternate}.bars.moving i:nth-child(2){animation-duration:1.1s;animation-delay:-.5s}.bars.moving i:nth-child(3){animation-duration:.7s;animation-delay:-.2s}.bars.moving i:nth-child(4){animation-duration:1s;animation-delay:-.7s}@keyframes bars{0%{transform:scaleY(.2)}to{transform:scaleY(1)}}@media(prefers-reduced-motion:reduce){.bars.moving i{animation:none;transform:scaleY(.6)}}#intro{position:fixed;left:50%;top:36%;transform:translate(-50%,-50%);display:grid;justify-items:center;gap:6px;max-width:min(640px,90vw);padding:22px 30px;border-radius:16px;background:color-mix(in srgb,var(--ink) 72%,transparent);border:1px solid var(--chip-border);text-align:center;pointer-events:none;opacity:0;visibility:hidden;transition:opacity .5s ease,visibility .5s}#intro.show{opacity:1;visibility:visible}#introTitle{font:700 clamp(22px,3vw,38px) / 1.15 var(--num);color:var(--text)}#introFacts{font-size:14px;color:var(--muted)}#introState{display:flex;align-items:center;gap:10px;margin-top:10px;font:600 12px var(--num);letter-spacing:.14em;text-transform:uppercase;color:var(--accent)}.sheet{position:fixed;right:32px;top:66px;z-index:2;width:min(400px,calc(100vw - 32px));max-height:calc(100vh - 118px);display:flex;flex-direction:column;border-radius:14px;overflow:hidden;background:color-mix(in srgb,var(--ink) 94%,transparent);backdrop-filter:blur(18px);border:1px solid var(--chip-border);box-shadow:0 24px 60px #0000008c}.sheet-head{display:flex;align-items:center;justify-content:space-between;padding:12px 12px 10px 18px}.sheet-head h2{margin:0;font:600 15px var(--ui)}.close{width:30px;height:30px;display:grid;place-items:center;padding:0;border:0;border-radius:8px;background:none;color:var(--muted);cursor:pointer}.close:hover{background:var(--chip);color:var(--text)}.tabs{display:grid;grid-template-columns:repeat(5,1fr);gap:2px;margin:0 14px;padding:3px;border-radius:9px;background:var(--chip);border:1px solid var(--chip-border)}.tabs button{padding:6px 0;border:0;border-radius:6px;background:none;font:500 13px var(--ui);color:var(--muted);cursor:pointer}.tabs button:hover{color:var(--text)}.tabs button[aria-selected=true]{background:var(--text);color:var(--ink);font-weight:600}.pane{display:grid;align-content:start;gap:18px;padding:18px 18px 20px;overflow:hidden auto}.pane h3{margin:0 0 -6px;font:600 11px var(--num);letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}.pane h3~h3{padding-top:16px;border-top:1px solid var(--chip-border)}.setting{display:grid;gap:8px}.pair{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:18px 20px}.setting-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px;font-size:13px;font-weight:500}.setting-head output{font:600 12px var(--num);color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}.setting .seg{overflow:visible}.setting .seg button{flex:1}.scale{display:flex;justify-content:space-between;margin-top:-4px;font-size:11px;color:var(--muted)}.hint{margin:-2px 0 0;font-size:12px;line-height:1.4;color:var(--muted)}.text-button{justify-self:start;padding:4px 0;border:0;background:none;font:500 12px var(--ui);color:var(--muted);text-decoration:underline;text-underline-offset:3px;cursor:pointer}.text-button:hover{color:var(--text)}:is(#settings,.volume) input[type=range]{-webkit-appearance:none;appearance:none;height:18px;margin:0;background:none;cursor:pointer}#settings input[type=range]{width:100%}:is(#settings,.volume) input[type=range]::-webkit-slider-runnable-track{height:4px;border-radius:2px;background:linear-gradient(90deg,var(--accent) var(--fill, 50%),var(--chip-border) var(--fill, 50%))}:is(#settings,.volume) input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:16px;height:16px;margin-top:-6px;border-radius:50%;background:var(--text);border:3px solid var(--accent);box-shadow:0 1px 4px #0006}:is(#settings,.volume) input[type=range]::-moz-range-track{height:4px;border-radius:2px;background:var(--chip-border)}:is(#settings,.volume) input[type=range]::-moz-range-progress{height:4px;border-radius:2px;background:var(--accent)}:is(#settings,.volume) input[type=range]::-moz-range-thumb{width:10px;height:10px;border-radius:50%;background:var(--text);border:3px solid var(--accent)}.toggle{display:flex;align-items:center;justify-content:space-between;gap:16px;font-size:13px;font-weight:500;cursor:pointer}.toggle small{display:block;margin-top:2px;font-size:12px;font-weight:400;line-height:1.4;color:var(--muted)}.toggle input{-webkit-appearance:none;appearance:none;flex:none;position:relative;width:36px;height:20px;margin:0;border-radius:10px;background:var(--chip-border);cursor:pointer;transition:background .15s}.toggle input:after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--text);transition:transform .15s}.toggle input:checked{background:var(--accent)}.toggle input:checked:after{transform:translate(16px);background:var(--ink)}.cards{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px}.cards.three{grid-template-columns:repeat(3,minmax(0,1fr))}.cards button{display:grid;gap:8px;justify-items:start;padding:10px;border-radius:9px;border:1px solid var(--chip-border);background:var(--chip);font:500 12px var(--ui);color:var(--muted);text-align:left;cursor:pointer}.cards button:hover{color:var(--text)}.cards button[aria-pressed=true]{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent);color:var(--text)}.dots{display:flex;gap:4px}.dots i{width:10px;height:10px;border-radius:50%;box-shadow:inset 0 0 0 1px #ffffff2e}.headstock{width:100%;height:52px}.order{font:600 12px var(--num);letter-spacing:.12em;color:var(--text)}#legend{width:min(430px,calc(100vw - 32px))}.legend-find{padding:0 14px 6px}.legend-find input{width:100%;height:34px;padding:0 12px;border-radius:9px;border:1px solid var(--chip-border);background:var(--chip);color:var(--text);font:13px var(--ui)}.legend-find input::placeholder{color:var(--muted)}.legend{gap:4px;padding-top:10px}.legend h3{margin:14px 0 4px}.legend h3:first-child{margin-top:0}.legend-item{display:grid;grid-template-columns:64px 1fr;gap:12px;align-items:center;padding:4px 0}.legend-item b{display:block;font-size:13px;font-weight:500}.legend-item span{display:block;font-size:12px;line-height:1.4;color:var(--muted)}.legend-item .keys{display:flex;justify-content:center;gap:4px}.legend-item kbd{min-width:22px;padding:2px 6px;border:1px solid var(--chip-border);border-bottom-width:2px;border-radius:5px;background:var(--chip);font:600 12px var(--num);text-align:center;white-space:nowrap}.legend-item svg{width:64px;height:36px;border-radius:8px;background:var(--chip);border:1px solid var(--chip-border);fill:none;stroke-linecap:round;stroke-linejoin:round}.legend-item text{font-family:var(--num);font-weight:700;text-anchor:middle;dominant-baseline:central}.legend-empty{margin:8px 0;font-size:13px;color:var(--muted)}.f0{fill:var(--s0)}.f1{fill:var(--s1)}.f2{fill:var(--s2)}.f3{fill:var(--s3)}.f4{fill:var(--s4)}.l0{stroke:var(--s0)}.l1{stroke:var(--s1)}.l2{stroke:var(--s2)}.l3{stroke:var(--s3)}.l4{stroke:var(--s4)}.lm{stroke:var(--muted)}.li{stroke:var(--ink)}.ft{fill:var(--text)}.lt{stroke:var(--text)}.fi{fill:var(--ink)}.fa{fill:var(--accent)}.fl{fill:var(--lane)}.ll{stroke:var(--lane)}.lw{stroke:#fff}.fm{fill:var(--muted)}.la{stroke:var(--accent)}.fw{fill:#fff}.volume{position:relative}.volume .icon.muted{color:var(--muted)}.volume-panel{position:absolute;top:calc(100% + 8px);left:50%;transform:translate(-50%);display:flex;align-items:center;gap:8px;padding:6px 14px 6px 6px;border-radius:10px;background:var(--ink);border:1px solid var(--chip-border);box-shadow:0 12px 30px #00000073}.volume-panel input{width:150px}.volume-panel output{min-width:36px;font:600 12px var(--num);color:var(--muted);text-align:right;font-variant-numeric:tabular-nums}.volume-mute{flex:none;width:30px;height:30px;display:grid;place-items:center;padding:0;border:0;border-radius:7px;background:none;color:var(--text);cursor:pointer}.volume-mute:hover{background:var(--chip)}.volume-mute[aria-pressed=true]{color:var(--muted)}#drop{position:fixed;inset:12px;z-index:5;display:grid;place-items:center;border:2px dashed var(--accent);border-radius:16px;background:#00000073;font:600 20px var(--num)}#tab{position:fixed;left:-10000px;top:0;width:1000px}@media(max-width:900px){.time{display:none}:root:where([data-fretfall-dock]) .time{display:block}#menuButton{display:grid}.volume{position:static}.volume-panel{left:auto;right:0;transform:none}.menu{display:none;position:absolute;top:calc(100% + 8px);right:0;width:230px;flex-direction:column;gap:2px;padding:6px;border-radius:12px;background:var(--ink);border:1px solid var(--chip-border);box-shadow:0 12px 30px #00000073}#menuButton[aria-expanded=true]+.menu{display:flex}.menu .icon{width:100%;height:38px;display:flex;justify-content:flex-start;gap:12px;padding:0 10px;border:0;border-radius:7px;background:none;font:500 13px var(--ui)}.menu .icon:after{content:attr(data-label)}.menu .icon:hover{background:var(--chip)}.menu .icon[aria-pressed=true],.menu .icon[aria-expanded=true]{background:none;color:var(--accent)}.menu .tip{display:none}.menu .divider{width:auto;height:1px;margin:4px}}@media(max-width:560px){.bar{flex-wrap:wrap;height:auto;row-gap:8px}.bar>.group:first-child,.bar>.group:last-child{flex:1 1 100%;height:40px}.speed{margin-left:auto}#menuButton{position:absolute;top:2px;right:0}.menu{top:48px}#phrases{top:122px}#info{flex-direction:column;align-items:flex-start;gap:2px;font-size:12px}#info>span+span:before{display:none}#info>span:first-child{max-width:100%;overflow:hidden;text-overflow:ellipsis}#progress{top:182px}#lyrics{top:212px}.sheet{top:114px;max-height:calc(100vh - 166px)}}@media(max-width:520px){.sheet{right:16px}}</style>
15
15
  <link rel="modulepreload" href="player.js">
16
16
  <link rel="modulepreload" href="fingering.js">
17
17
  <link rel="modulepreload" href="highway.js">
@@ -177,7 +177,8 @@ stroke-linejoin="round"
177
177
  <span class="tip" role="tooltip" id="loopTip"
178
178
  ><b>Loop <kbd>L</kbd></b
179
179
  >Loop the phrase you are in. Drag across the phrase
180
- bars to loop a stretch, or shift-click one to
180
+ bars to loop a stretch, hold shift while dragging to
181
+ loop exactly what you pick, or shift-click a bar to
181
182
  stretch the loop to it</span
182
183
  >
183
184
  </button>
package/mount.d.ts ADDED
@@ -0,0 +1,81 @@
1
+ // The player mounted in an element of a page that isn't its own, and the hook that page talks to it through:
2
+ // window.fretfall, and the fretfall:* events on window (see the README)
3
+
4
+ /** A kind of song file the player doesn't read itself, added with `fretfall.addFormat`. */
5
+ export interface FretfallFormat<Options = Record<string, unknown>> {
6
+ /** As the Open dialog says it: "a .pak". */
7
+ name: string;
8
+ /** Lower case, with the dot: `[".pak"]`. */
9
+ extensions: string[];
10
+ /** `options`: what `fretfall.open` was given, and `status(text)` to say what is taking the time. */
11
+ open(file: File, options: Options & { status(text: string): void }): Promise<{ song: unknown; audio?: Blob | null }>;
12
+ }
13
+
14
+ export interface Fretfall {
15
+ /** Open songs: a tab, or a tab with its recording. `options` are handed on to the format that opens a file. */
16
+ open(files: Iterable<File>, options?: Record<string, unknown>): Promise<void>;
17
+ /** Show the file dialog. */
18
+ pick(): void;
19
+ /** Settable: `true` waits for the synth's instruments if the song has just opened. */
20
+ playing: boolean;
21
+ /** Seconds into the song. Settable: a jump to there, kept within the song. */
22
+ time: number;
23
+ /** The song's length in seconds, 0 without a song. */
24
+ readonly length: number;
25
+ /** How fast it plays: 1 is the song's own tempo. Settable, in the player's steps of a tenth from 0.1 to 1.5. */
26
+ speed: number;
27
+ /**
28
+ * What the instrument looks like: the note shape (`look`), the colour set (`colors`), the fonts, the string colours
29
+ * (`strings`) and the headstock. Settable whole or in part; a name the player does not know is ignored, so add a
30
+ * colour set of your own to `COLORS` in `themes.js` before naming it here.
31
+ */
32
+ style: { look: string; colors: string; fonts: string; strings: string; headstock: string };
33
+ /**
34
+ * What the part shown is asking for, or null without a song: `open`, the open strings' midi notes lowest string
35
+ * first, and every note as `time` and `sustain` in seconds, `string` (0 is the lowest), `fret`, and the `midi` note
36
+ * it sounds. A copy, made on each read: read it once a song, not each frame.
37
+ */
38
+ readonly notes: { open: number[]; notes: { time: number; sustain: number; string: number; fret: number; midi: number }[] } | null;
39
+ /** The names of the song's parts. */
40
+ readonly parts: string[];
41
+ /** The part shown, -1 without one. Settable. */
42
+ part: number;
43
+ addFormat(format: FretfallFormat<any>): void;
44
+ /** Close Settings and the notation sheet. */
45
+ closeSheets(): void;
46
+ /**
47
+ * Move the header's controls (the part picker, time, speed, volume, loop, play, open, help, settings, full screen)
48
+ * into `element`, an element of the page's own bar say, and hide the header meanwhile: the page has one bar and
49
+ * the highway the row. Help, settings and full screen go into `more` instead when given. Both are marked
50
+ * `data-fretfall` and `data-fretfall-dock`, so the player's styles reach the controls. `null` brings them home.
51
+ */
52
+ dock(element: HTMLElement | null, more?: HTMLElement): void;
53
+ }
54
+
55
+ export interface FretfallSong {
56
+ /** The file's name; null for a band window's song. */
57
+ file: string | null;
58
+ title?: string;
59
+ artist?: string;
60
+ parts: string[];
61
+ part: number;
62
+ }
63
+
64
+ /**
65
+ * Mounts the player in `element`, which has to be in the page and have a size. Once a page: there is no unmount, and a
66
+ * second call returns the first one's promise, so keep the element and hide it rather than removing it.
67
+ * Resolves to `window.fretfall` once `fretfall:ready` has fired.
68
+ */
69
+ export function mount(element: HTMLElement): Promise<Fretfall>;
70
+
71
+ declare global {
72
+ var fretfall: Fretfall | undefined; // window.fretfall too
73
+ interface WindowEventMap {
74
+ 'fretfall:ready': CustomEvent<null>;
75
+ 'fretfall:song': CustomEvent<FretfallSong>;
76
+ 'fretfall:playing': CustomEvent<{ playing: boolean }>;
77
+ /** Played out to its end, rather than paused. */
78
+ 'fretfall:ended': CustomEvent<null>;
79
+ 'fretfall:sheet': CustomEvent<{ name: 'settings' | 'legend'; open: boolean }>;
80
+ }
81
+ }