Replies: 1 comment 2 replies
-
|
I plan to rework this area quite significantly in a breaking change release alphaTab 2.0. Over the years we gradually added more and more ways of configuring certain things and it is quite overdue to consoldate things. Most things in the The idea is to get closer to what also applications like Dorico and Musescore allow: define a default stylesheet with file-level and model-element-level overrides on how things should be displayed. Colors, paddings, line thicknesses scale etc. should then be configurable on those level in a fine-grained thought through structure. This will then replace all the current RenderResources, individual paddings, SMuFL aspects. At this stage the model walk is the intended way to apply custom styles for the specific usecases. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
First, thank you for alphaTab — it's a genuinely impressive piece of engineering, and I mean that as someone who's spent a fair bit of time in the rendering internals for this. This is a "wouldn't it be nice" idea, not a request I expect to jump the queue — happy for it to just sit here as a discussion, and no hard feelings if it's not the direction you want to take things.
The idea
Today,
mainGlyphColoris used as the default color for fret-number digits, note stems/beams, and bend/slide effect glyphs alike — there's no way to theme these differently from one another globally.What's interesting (and part of why I thought this might be a reasonable ask) is that the underlying rendering code already seems to model these as distinct things, if I'm reading it right:
NoteSubElement.GuitarTabFretNumber,BeatSubElement.GuitarTabStem,BeatSubElement.GuitarTabBeams, andNoteSubElement.GuitarTabEffects/BeatSubElement.GuitarTabEffectsall look like separate enum values, and the renderer already seems to scope color application per sub-element viaElementStyleHelper— e.g.NoteNumberGlyphappears to explicitly paint underNoteSubElement.GuitarTabFretNumber. So the semantic distinction looks like it's already there in the type system and the draw pipeline; I just can't find a global default that uses it.The gap, as far as I can tell, is in
ElementStyleHelper._noteDefaultColor/_beatDefaultColor: regardless of which sub-element is being painted, the default color resolves to the samemainGlyphColor(orsecondaryGlyphColorfor voice index ≠ 0). The only way to differentiate today looks likeNote.style/Beat.style(a per-instanceMap<SubElement, Color>) — which would mean walking every note/beat in a score to set overrides by hand. It'd be lovely if there were a Settings-level default that already distinguished them, so this could be done once globally instead.Below is what that per-instance override already produces today, for a small tab example — the point being that alphaTab can clearly draw this distinction, it's just not exposed as a global default:
A pattern that already seems to exist for this
RenderingResourcesalready seems to do exactly this for fonts:elementFonts: Map<NotationElement, Font>, backed by a staticdefaultFontsmap, resolved with fallback. I didn't find an equivalent for colors keyed byNoteSubElement/BeatSubElement— but if I've missed one, please let me know, that'd make this whole request moot in the best way.What I'd love to see (happy to be told this is harder than it looks)
Something like default-color maps on
RenderingResources, mirroringelementFonts— e.g.noteSubElementColors: Map<NoteSubElement, Color>andbeatSubElementColors: Map<BeatSubElement, Color>— consulted by_noteDefaultColor/_beatDefaultColorbefore falling back tomainGlyphColor/secondaryGlyphColoras today. Ideally additive and backward compatible — anything left unset just keeps behaving exactly as it does now.If that feels like too much new surface area, a smaller version would still help a lot: just two or three new flat resource-color fields (
fretNumberColor,effectGlyphColoror similar) checked before themainGlyphColorfallback for the relevant sub-elements. Less general, but a much smaller ask if that's preferable.One thing I'm genuinely unsure about: SVG vs. HTML5 Canvas parity
alphaTab renders to both SVG and HTML5 Canvas, and I don't want to propose something that would make those two diverge in capability.
From what I can tell, this specific piece looks like it should be fine: the color-resolution logic in
ElementStyleHelperonly ever reads fromRenderingResources/the note-beat model and writes tocanvas.colorthrough the sharedICanvasinterface — it doesn't appear to touch anything platform-specific. BothSvgCanvasandHtml5Canvasimplement that sameICanvasinterface and just readcanvas.colorat the point of drawing. So as far as I can tell, this resolution happens above the platform split entirely, and both backends would pick up the change equally with no separate implementation needed for either one. But I'd genuinely welcome correction here if there's some Canvas-specific wrinkle I haven't found.(For context, I separately looked into a related idea — emitting CSS classes per resource role on rendered SVG elements — and that one is a different story: it's inherently SVG/DOM-specific and wouldn't have a Canvas equivalent, since there's no DOM to attach a class to when drawing to a
<canvas>. This proposal felt meaningfully different in that respect, since it's about color resolution rather than DOM output.)Related discussion
I came across #1048 ("Dark mode score rendering") and #1558 ("Is it possible to customize appearance?") while searching — #1048 is about switching whole color presets, and #1558 is about API ergonomics for constructing
Color/Fontinstances. Neither seemed to cover this specifically, but flagging them in case I've missed the connection.I also posted a separate, narrower idea recently — #2758, about emitting a stable CSS class per
display.resourcesrole on rendered SVG elements. That one and this one are aimed at different layers of the same underlying gap, and I think they're complementary rather than overlapping:mainGlyphColorcovers several visually distinct things.If both landed, the ideal combination would probably be classes per sub-role (e.g.
at-role-noteSubElement-GuitarTabFretNumber) rather than just per top-level resource — but either one alone would already be a real improvement over what's possible today, and they don't depend on each other to be useful individually.Thank you again for all the work that's gone into this — even if this particular idea doesn't go anywhere, I appreciate you taking the time to read it.
Beta Was this translation helpful? Give feedback.
All reactions