k-l-lambda commited on
Commit
eb7dc71
·
1 Parent(s): 51e9bed

fixed player loading status.

Browse files
Files changed (3) hide show
  1. app.py +3 -2
  2. web/score-player.css +32 -0
  3. web/score-player.js +27 -2
app.py CHANGED
@@ -436,9 +436,10 @@ def build_head ():
436
  # left under Compose + Logs (robust against Gradio's flex-nesting quirks).
437
  os.path.join(WEB_DIR, 'layout-fit.js'),
438
  ]
439
- tags = ['<script>window.__LILYSCRIPT_SOUNDFONT_URL=%r;window.__LILYSCRIPT_FLUID_URL=%r;</script>'
440
  % (_file_url(os.path.join(WEB_DIR, 'soundfont')) + '/',
441
- _file_url(os.path.join(WEB_DIR, 'fluid')) + '/')]
 
442
  tags.append('<link rel="stylesheet" href="%s">' % _file_url(os.path.join(WEB_DIR, 'score-player.css')))
443
  tags.append('<link rel="stylesheet" href="%s">' % _file_url(os.path.join(WEB_DIR, 'lyl-editor.css')))
444
  for s in scripts:
 
436
  # left under Compose + Logs (robust against Gradio's flex-nesting quirks).
437
  os.path.join(WEB_DIR, 'layout-fit.js'),
438
  ]
439
+ tags = ['<script>window.__LILYSCRIPT_SOUNDFONT_URL=%r;window.__LILYSCRIPT_FLUID_URL=%r;window.__LILYSCRIPT_LOADING_RENDERER=%s;</script>'
440
  % (_file_url(os.path.join(WEB_DIR, 'soundfont')) + '/',
441
+ _file_url(os.path.join(WEB_DIR, 'fluid')) + '/',
442
+ json.dumps(T('loading_renderer')))]
443
  tags.append('<link rel="stylesheet" href="%s">' % _file_url(os.path.join(WEB_DIR, 'score-player.css')))
444
  tags.append('<link rel="stylesheet" href="%s">' % _file_url(os.path.join(WEB_DIR, 'lyl-editor.css')))
445
  for s in scripts:
web/score-player.css CHANGED
@@ -223,3 +223,35 @@
223
  #ls-score .ls-sf.ready .ls-sf-check {
224
  display: inline;
225
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  #ls-score .ls-sf.ready .ls-sf-check {
224
  display: inline;
225
  }
226
+
227
+ /* In-panel renderer-loading overlay: shown inside the freshly-mounted score panel
228
+ while the 7.6MB verovio bundle is still downloading (score-player.js mounts early,
229
+ before verovio finishes — see app.py head order). Mirrors the static placeholder
230
+ spinner so the loading feedback is continuous across the mount handover. Removed
231
+ (display:none) once verovio is ready or a score has rendered. */
232
+ #ls-score .ls-renderer-loading {
233
+ display: flex;
234
+ flex-direction: column;
235
+ align-items: center;
236
+ justify-content: center;
237
+ min-height: 240px;
238
+ color: #999;
239
+ text-align: center;
240
+ }
241
+ #ls-score .ls-renderer-loading .ls-loading-spinner {
242
+ width: 38px;
243
+ height: 38px;
244
+ margin-bottom: 14px;
245
+ border: 4px solid #e3e3ea;
246
+ border-top-color: #7c5cff;
247
+ border-radius: 50%;
248
+ animation: ls-spin 0.8s linear infinite;
249
+ }
250
+ #ls-score .ls-renderer-loading .ls-loading-text {
251
+ font-size: 14px;
252
+ }
253
+ @media (prefers-reduced-motion: reduce) {
254
+ #ls-score .ls-renderer-loading .ls-loading-spinner {
255
+ animation: ls-spin 2.4s linear infinite;
256
+ }
257
+ }
web/score-player.js CHANGED
@@ -20,6 +20,10 @@
20
  'use strict';
21
 
22
  const SOUNDFONT_URL = window.__LILYSCRIPT_SOUNDFONT_URL || './soundfont/';
 
 
 
 
23
 
24
  const state = {
25
  toolkit: null, // Verovio toolkit
@@ -178,6 +182,7 @@
178
  const pages = [];
179
  for (let pg = 1; pg <= pageCount; pg++) pages.push(tk.renderToSVG(pg));
180
  injectSvg(pages);
 
181
  state.lastCode = code;
182
  state.lastMei = mei;
183
  setStatus('', '');
@@ -560,7 +565,15 @@
560
  const svgBox = document.createElement('div'); svgBox.className = 'ls-svg';
561
  const cursor = document.createElement('div'); cursor.className = 'ls-cursor';
562
  svgBox.appendChild(cursor);
563
- wrap.appendChild(status); wrap.appendChild(svgBox);
 
 
 
 
 
 
 
 
564
 
565
  // transport bar (above the score)
566
  const player = document.createElement('div'); player.className = 'ls-player'; player.style.display = 'none';
@@ -577,6 +590,7 @@
577
  root.appendChild(player); root.appendChild(wrap);
578
 
579
  els.root = root; els.svg = svgBox; els.preview = wrap; els.status = status; els.player = player; els.cursor = cursor;
 
580
  els.playBtn = player.querySelector('.ls-play');
581
  els.pauseBtn = player.querySelector('.ls-pause');
582
  els.stopBtn = player.querySelector('.ls-stop');
@@ -616,7 +630,10 @@
616
  if (typeof time === 'number' && !isNaN(time) && time >= 0) seekTo(time);
617
  });
618
 
619
- initVerovio(); // warm up early
 
 
 
620
  // Start loading the sound library (FluidSynth GM soundfont, ~40MB) right away
621
  // at page mount rather than deferring to the first play — the AudioContext is
622
  // created suspended (no autoplay-policy violation) and the fetch/worklet load
@@ -625,6 +642,14 @@
625
  initAudio();
626
  }
627
 
 
 
 
 
 
 
 
 
628
  // Public API consumed by app.py's injected glue.
629
  window.LilyScore = {
630
  mount: mount,
 
20
  'use strict';
21
 
22
  const SOUNDFONT_URL = window.__LILYSCRIPT_SOUNDFONT_URL || './soundfont/';
23
+ // Label for the in-panel renderer-loading spinner. app.py sets the i18n'd string on
24
+ // window.__LILYSCRIPT_LOADING_RENDERER (matches the static placeholder's T('loading_renderer'));
25
+ // fall back to English if it's absent (e.g. score-player.js loaded standalone).
26
+ const LOADING_RENDERER_TEXT = window.__LILYSCRIPT_LOADING_RENDERER || 'Loading score renderer…';
27
 
28
  const state = {
29
  toolkit: null, // Verovio toolkit
 
182
  const pages = [];
183
  for (let pg = 1; pg <= pageCount; pg++) pages.push(tk.renderToSVG(pg));
184
  injectSvg(pages);
185
+ setRendererLoading(false); // score is now visible — ensure the loading spinner is gone
186
  state.lastCode = code;
187
  state.lastMei = mei;
188
  setStatus('', '');
 
565
  const svgBox = document.createElement('div'); svgBox.className = 'ls-svg';
566
  const cursor = document.createElement('div'); cursor.className = 'ls-cursor';
567
  svgBox.appendChild(cursor);
568
+ // Renderer-loading overlay: a spinner shown INSIDE the freshly-mounted panel while
569
+ // the 7.6MB verovio bundle is still downloading. Since score-player.js now mounts
570
+ // early (before verovio finishes — see app.py head order), without this the panel
571
+ // would sit blank with no feedback during the wait (the static placeholder is gone,
572
+ // replaced by this mount). Removed once verovio is ready (setRendererLoading(false)).
573
+ const loading = document.createElement('div'); loading.className = 'ls-renderer-loading';
574
+ loading.innerHTML = '<div class="ls-loading-spinner" aria-hidden="true"></div>' +
575
+ '<div class="ls-loading-text">' + LOADING_RENDERER_TEXT + '</div>';
576
+ wrap.appendChild(status); wrap.appendChild(svgBox); wrap.appendChild(loading);
577
 
578
  // transport bar (above the score)
579
  const player = document.createElement('div'); player.className = 'ls-player'; player.style.display = 'none';
 
590
  root.appendChild(player); root.appendChild(wrap);
591
 
592
  els.root = root; els.svg = svgBox; els.preview = wrap; els.status = status; els.player = player; els.cursor = cursor;
593
+ els.loading = loading;
594
  els.playBtn = player.querySelector('.ls-play');
595
  els.pauseBtn = player.querySelector('.ls-pause');
596
  els.stopBtn = player.querySelector('.ls-stop');
 
630
  if (typeof time === 'number' && !isNaN(time) && time >= 0) seekTo(time);
631
  });
632
 
633
+ // Show the renderer-loading spinner until verovio is ready; initVerovio() resolves
634
+ // when the (possibly still-downloading) verovio bundle has constructed its toolkit.
635
+ setRendererLoading(!state.verovioReady);
636
+ initVerovio().then(function (tk) { setRendererLoading(false); }); // warm up early; clears spinner when ready
637
  // Start loading the sound library (FluidSynth GM soundfont, ~40MB) right away
638
  // at page mount rather than deferring to the first play — the AudioContext is
639
  // created suspended (no autoplay-policy violation) and the fetch/worklet load
 
642
  initAudio();
643
  }
644
 
645
+ // Toggle the in-panel renderer-loading spinner (verovio still downloading). Hidden
646
+ // once a score has actually rendered (an SVG is present) so it never overlaps content.
647
+ function setRendererLoading (flag) {
648
+ if (!els.loading) return;
649
+ var hasSvg = els.svg && els.svg.querySelector('svg');
650
+ els.loading.style.display = (flag && !hasSvg) ? '' : 'none';
651
+ }
652
+
653
  // Public API consumed by app.py's injected glue.
654
  window.LilyScore = {
655
  mount: mount,