Skip to content

Slur of a legato slide / hammer-on between two-note chords is not drawn in the standard notation staff when beats are tightly spaced (path with NaN) #2904

Closed

Description

@shimabox

Is there an existing issue for this?

  • I have searched the existing issues

I have read the contribution rules

AI authorship

AI-assisted (disclosure block included as described in AGENTS.md)

Current Behavior

Note

AI-authored disclosure (alphatab-ai-authored-v1)

Portions of this content were authored by an AI agent. The agent has read
AGENTS.md and the human submitter accepts responsibility for
compliance with the rules in that document.

When a two-note chord with a legato slide ({sl}) or hammer-on ({h}) is followed by tightly spaced beats, the slur between the two chords is missing from the standard notation staff. The browser console shows an error for the slur's SVG path, whose control points are NaN:

Error: <path> attribute d: Expected number, "…0000001,44.915 CNaN,NaN,NaN,NaN,…".

The d attribute of the affected path (1.8.4, render width 400px):

M122.80787500000001,44.915 CNaN,NaN,NaN,NaN,132.5,49.415 CNaN,NaN,NaN,NaN,122.80787500000001,44.915 z

Whether it happens depends on how tightly the beats are laid out, so the same score renders correctly at one width and loses the slur at a narrower one. Number of paths containing NaN for the snippet below, by render width:

Version 1200px 600px 400px 300px
1.8.4 0 0 1 1
1.9.0-alpha.1891 0 1 1 1

Observations with the same snippet at 400px:

  • {h} instead of {sl}: same result.
  • Without the legato effect: no NaN path.
  • Single notes instead of two-note chords: no NaN path.
  • \staff {tabs} only: no NaN path (the tab staff draws its arc). \staff {score} only: the NaN path appears.

Expected Behavior

The slur between the two chords is drawn in the standard notation staff at any render width (it may be very short when the beats are close together), and no SVG path with NaN is produced.

Steps To Reproduce

  1. Render this alphaTex with the SVG engine (core.useWorkers = false, core.enableLazyLoading = false) into a container that is 400px wide:
    \staff {score tabs}
    \tuning e4 b3 g3 d3 a2 e2
    \ts 4 4
    (14.1{sl} 11.3{sl}).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16
    (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16
    (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16
    (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 |
    
  2. Open the browser console: the Expected number, "… CNaN,NaN,NaN,NaN,…" error appears.
  3. In the standard notation staff, there is no slur between the first and the second chord. The tab staff shows its arc.
  4. Render the same snippet into a 1200px wide container: no error, the slur is drawn.

Link to jsFiddle, CodePen, Project

https://jsfiddle.net/shimabox/6csLz4px/

Version and Environment

[AlphaTab][VersionInfo] alphaTab 1.8.4
[AlphaTab][VersionInfo] commit: 022a45c8e42370f9e12e68949d11eada370da83d
[AlphaTab][VersionInfo] build date: 2026-07-05T14:46:18.224Z
[AlphaTab][VersionInfo] High DPI: 1
[AlphaTab][VersionInfo] Platform: Browser
[AlphaTab][VersionInfo] WebPack: false
[AlphaTab][VersionInfo] Vite: false
[AlphaTab][VersionInfo] Browser: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/154.0.0.0 Safari/537.36
[AlphaTab][VersionInfo] Window Size: 953x826
[AlphaTab][VersionInfo] Screen Size: 1200x800

Also reproduced with:

[AlphaTab][VersionInfo] alphaTab 1.9.0-alpha.1891
[AlphaTab][VersionInfo] commit: 2a460d7c4b6d879465fe23382adc67bf6fd3196d
[AlphaTab][VersionInfo] build date: 2026-08-10T02:28:09.977Z

Platform

Web

Anything else?

Screenshots of the snippet with 1.8.4.

600px wide (no NaN path; the slur in the standard notation staff is drawn, but only about 6px wide, between the first chord and the accidentals of the second chord):

Image

400px wide (slur missing in the standard notation staff):

Image

Single-file reproduction (loads alphaTab from jsDelivr; ?v= selects the version, ?w= the container width, ?case=sl|h|none the snippet):

repro.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>alphaTab legato slur NaN repro</title>
<style>
  body { font-family: sans-serif; margin: 16px; }
  #surface { border: 1px dashed #aaa; }
  pre { background: #f4f4f4; padding: 8px; }
</style>
</head>
<body>
<p>version: <b id="ver"></b> / width: <b id="wid"></b> / NaN paths: <b id="nan">…</b></p>
<pre id="tex"></pre>
<div id="surface"></div>
<script>
  // Usage: repro.html?v=1.8.4&w=500&case=sl
  var q = new URLSearchParams(location.search);
  var version = q.get("v") || "1.8.4";
  var width = parseInt(q.get("w") || "500", 10);
  var cases = {
    // two-note chords, 16th notes, legato slide into the next beat
    sl: "\\tuning e4 b3 g3 d3 a2 e2\n\\ts 4 4\n" +
        "(14.1{sl} 11.3{sl}).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 |",
    // same rhythm, hammer-on instead of slide
    h:  "\\tuning e4 b3 g3 d3 a2 e2\n\\ts 4 4\n" +
        "(14.1{h} 11.3{h}).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 |",
    // control: no legato effect
    none: "\\tuning e4 b3 g3 d3 a2 e2\n\\ts 4 4\n" +
        "(14.1 11.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 " +
        "(16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 (16.1 13.3).16 |"
  };
  var tex = q.get("tex") || cases[q.get("case") || "sl"];
  document.getElementById("ver").textContent = version;
  document.getElementById("wid").textContent = width + "px";
  document.getElementById("tex").textContent = tex;
  var surface = document.getElementById("surface");
  surface.style.width = width + "px";
  window.__result = null;

  var base = "https://cdn.jsdelivr.net/npm/@coderline/alphatab@" + version + "/dist/";
  var s = document.createElement("script");
  s.src = base + "alphaTab.min.js";
  s.onload = function () {
    var api = new alphaTab.AlphaTabApi(surface, {
      core: { useWorkers: false, enableLazyLoading: false, fontDirectory: base + "font/" },
      player: { enablePlayer: false }
    });
    api.renderFinished.on(function () {
      var bad = Array.prototype.filter.call(surface.querySelectorAll("path"), function (p) {
        return /NaN/.test(p.getAttribute("d") || "");
      });
      document.getElementById("nan").textContent = String(bad.length);
      window.__result = { version: version, width: width, nan: bad.length,
        sample: bad.length ? bad[0].getAttribute("d").slice(0, 120) : "" };
    });
    api.tex(tex);
  };
  document.head.appendChild(s);
</script>
</body>
</html>

Activity

  1. added theissue type on Oct 4, 2026
  2. updated Priority Low, Area Rendering, Platform All / Multiple, Work State Needs Investigation and Effort Medium on Oct 5, 2026
  3. Danielku15 commented on Oct 5, 2026

    @Danielku15
    Member

    I have to check whether this is actually a bug as described. You are squeezing the notation to a size where it cannot fit anymore. there are overlaps in the notation which clearly indicate this. alphaTab cannot solve you the problem of not giving it enough space to fit. we rather let overlaps at the cost of problematic display. the alternative would be to not scale the notation smaller, but then it would overlap the available container.

    I'll check if we can improve anything here.

  4. added this to the 1.9.0 milestone on Oct 5, 2026
  5. Danielku15 commented on Oct 9, 2026

    @Danielku15
    Member

    I made various improvements in #2943 and #2944 but the core problem remains as described: if there is not enough space for the notation to fit, it will cause overlaps. If you have concrete needs it it might be better to open a GitHub Discussion to show your concrete app setup so we can plan more detailed what new features alphaTab could get (mid-bar system breaks, alternative sizing modes and callbacks to ensure the min-size,...)

    in #2943 I improved various slur placement and spacing aspects and warn about the situation that there is not enough space via the logger.

  6. shimabox commented on Oct 9, 2026

    @shimabox
    Author

    Thanks for the fixes and the detailed explanation! I understand that overlaps can still occur when there isn’t enough width. Thanks also for pointing me to Discussions for questions about the layout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Fields

Priority

Low

Effort

Medium

Area

Rendering

Platform

All / Multiple

Work State

Needs Investigation

Projects

Relationships

None yet

Development

No branches or pull requests

Issue actions