Musicaltypesetting
mScore.js
and more

The sprite model of mScore.js

For performance reasons most graphics rendering of mScore.js is performed by copying pre-rendered sprites onto the canvas. These are stored in an mScore.Renderer object, which is usually created once on loading a web page, then used to render all musical materials on that page. The process of creating an mScore.js renderer is as follows:

var myRenderer = new mScore.Renderer();
/* Code to set renderer parameters / modify sprite descriptions goes here */
myRenderer.Const.lineWidth = 12; // for example: set width between two lines of a stave to 12px;
                                 // lineWidth is the most common parameter to set.
myRenderer.initialize();

Creating the renderer object (line 1 above) sets the renderer's constants and creates its sprite description objects (both stored in Renderer.Const). These can afterwards be modified at will. Finally a call of Renderer.initialize() renders the sprite descriptions into sprites. Adter this the renderer can be used to display content. It is strongly discouraged to modify mScore.js’s source files themselves to modify sprite descriptions. Please use the mechanism described here to do that.

All sprites use Renderer.Const.lineWidth as their basic length unit, all other lengths are stored as multiples of it. Renderer.Const.r is the (half) thickness of stave lines, note stems etc. Usually these two parameters are the only ones that need to be modified.

ParameterdefaultDescription
lineWidthpxCentral unit. Height of the whole stave is obviously 4·lineWidth. Must be an even number, so that notes of all pitches can be drawn at whole pixel positions.
rHalf thickness of stave lines, note stems and bar lines. Given as a multiple of lineWidth (like all other lengths unless mentioned).
staveShiftpxPixel amount by which the center of stave lines is shifted vertically (> 0 = downwards) away from whole pixels. Relevant for visual display (smoothing) at smaller sizes. Use values between −1 and 1.
barlineShiftpxPixel amount by which the center of bar lines is shifted horizontally (> 0 = right) away from whole pixels. Relevant for visual display (smoothing) at smaller sizes. Use values between −1 and 1.
Origin
Sprite pivot
Local origin
toRef
(toR
toB
)
(toR
toB
)
(toL
toT
)
(toL
toT
)
Ref
Crn
Pvt

The mScore.js sprite path language

mScore.js uses its own vector graphics language to describe sprite outlines, which is broadly derived from SVG paths. The language is designed to be very concise and easy to parse while retaining reasonable human readability.

An mScore.js sprite path consists of operators (listed below) followed by the appropriate number of numerical arguments. If operators of the same type follow each other (often the case with L or C) the operator needs only be called once, it stays on until a different one is called (as in SVG). The following two code snippets (drawing a triangle) are equivalent:

M -11 3 L 11 3 L 0 -15 ZM -11 3 L 11 3 0 -15 Z

Spaces in the code can be omitted wherever they are not necessary: around operators or in front of numbers beginning with a “−”. The triangle code shown above can be shortened to

M-11 3L11 3 0-15Z

Spaces between positive numbers must remain, of course. There often is the case that a path consists of long sequences of numbers (coordinates) which are (signed) integers with a maximum number of digits. In these cases some more space can be saved by using the integer sequence operators D and X. Each one of them is immediately followed by a single digit which specifies the number of places in each of the integers following it. These integers can now be written without spaces between them (padding shorter numbers with zeros). An integer sequence can also (and usually does) contain operators. It ends at the end of the input, at a space, a different integer sequence, or at an evaluating expression. D takes decimal numbers, X takes hexadecimal numbers. Note that hexadecimal digits af must be lowercase so they don't collide with operators.

For example, in the triangle path from above no number has more than two digits; they can even be written with a single hexadecimal digit each, so we equivalently get

D2M-1103L110300-15ZX1M-b3Lb30-fZ

The path design helper tool provides a button to “compress” paths to a chosen integer format; usually 2 unsigned hexadecimal digits will be enough for reasonable visual accuracy, except with circular arcs, which therefore remain with floating-point coordinates.

CodeOperator#ArgsDescription
Transformation operators
RstReset transformation0Resets the current transformation to the initial value
ScScale coordinates2The path design tool only works with uniform scalings and reflections, but sprites also accept non-uniform scalings.
TrsTranslate coordinates2Calls canvas’ translate
TrpTranslate to pivot0Resets scaling and translates the origin to the pivot. Thus the command is equivalent to RstTrs@%Cen.x@@%Cen.y@. Will often be the first command of a sprite path.
TrcTranslate to corner0Resets scaling and translates the origin to the top left corner of specified bounding box. Thus the command is equivalent to RstTrs@%Crn.x@@%Crn.y@. Will often be the first command of a sprite path.
TflLinear transformation4Transforms the x axis into the vector given by the first two arguments, and the y axis into the vector of the last two arguments. Use this if you need a skew transformation.
Path construction operators
MMove to2Calls canvas’ moveTo
LLine to2Calls canvas’ lineTo
QQuadratic Bézier curve to4Calls canvas’ quadraticCurveTo
CCubic Bézier curve to6Calls canvas’ bezierCurveTo
ApCCW circular arc5Arguments are xcenter, ycenter, radius, start angle, end angle (in degrees).
AnCW circular arc5Arguments are xcenter, ycenter, radius, start angle, end angle (in degrees).
Misc. operators
ZClose path0Calls canvas’ closePath
RctConstruct rectangle4As with canvas’ rect, the third and fourth arguments are the rectangle’s width and height
AfConstruct circle3Construct a full circle, arguments are xcenter, ycenter and radius.
StrStroke path1Normally constructed paths are filled after all code has been processed. For special effects you can use this command to stroke what has been constructed so far, then start a new path. The argument is the line width to use.

As a practical example, here is the code for the G clef displayed above:

Sprite description objects and evaluating expressions

The sprite path language described so far can be used without creating/using an mScore.js renderer or a sprite description object. For example

var CT = document.getElementById('myCanvas')).getContext('2d');
CT.beginPath();
mScore.drawSpritePath.call(CT, 'X1M-b3Lb30-fZ'); // static function of mScore.Renderer
CT.fill();
If we do use a sprite description object to render a sprite, we gain the ability to use evaluating expressions in sprite paths. They are snippets of JavaScript code that can be evaluated (by JavaScript’s eval function) to a numerical value which is then used like any explicit numeric input. They are enclosed by $...$, @...@ or !...!. The difference is how the evaluated number is interpreted:

$...$The evaluated number is used as-is, i.e. in current local coordinates.
@...@The evaluated number divided by the sprite’s scale value. I.e. if no further explicit Sc (scaling) has been applied, it will be a pixel coordinate.
!...!If no further scaling has been applied, the number will be taken to be multiples of Renderer.Const.lineWidth.

The purpose of evaluating expressions is to use parameters of the sprite description and constants of the renderer (in Renderer.Const). Because sprite descriptions are constructed with a JavaScript prototype chain ending in Renderer.Const, all of these values can be addressed by this.myVariableName. To shorten this a bit and improve readability we allow addressing variables by %myVariableName. (% will simply be replaced by this. on rendering). If you need the modulo operator, simply put a space after it, that will prevent the replacement.

As an example, here is code to draw the head of a quarter note with a stub of a stem pointing upwards.

TrpSlc0 0$%R.x$$%R.y$$%R.lam$0$%a0$ L$%R.x-2*%r$@-2*%Pvt.y@ $%R.x$@-2*%Pvt.y@ Z