DevelopersScore Viewer React

Score Viewer React

@viritura/score-viewer-react wraps the Score Viewer in React components and hooks. It needs React 19.2 or later.

npm install @viritura/score-viewer-react

The package depends on @viritura/score-viewer and @viritura/score-engine, and re-exports the engine API, so one import is enough. In a bundled app, copy the engine's runtime files into your static assets and pass assetBaseUrl, as described in Serving the files.

Complete viewer

import { ScoreViewer } from "@viritura/score-viewer-react";

export function Example({ mnx }: { mnx: string }) {
  return <ScoreViewer mnx={mnx} defaultFitMode="width" defaultViewMode="page" enableCtrlWheelZoom />;
}

<ScoreViewer> fills its parent, so give the parent a height. It includes a control bar for view mode, zoom and fit. The first instance loads the engine, and later instances share it.

Controls

<ScoreViewer
  mnx={mnx}
  availableViewModes={["page", "spread", "horizon"]}
  controls={{ score: true, viewMode: true, zoom: true, fit: true, pageSize: true, staffSize: true }}
  controlSurface="toolbar"
  scoreOptions={[
    { index: 0, label: "Full score" },
    { index: 1, label: "Flute" },
  ]}
/>
  • controls is true, false or an object that turns individual controls on. Page size and staff size are hidden in horizon, which has no pages.
  • controlSurface is floating-status (default), toolbar or none.
  • scoreOptions lists MNX score definitions for the score selector. Get the names from engine.info(mnx).scores.
  • pageSizeOptions and staffSizeOptions fill the page-size and staff-size selectors.

Every control is available controlled or uncontrolled, in the usual React pattern: viewMode or defaultViewMode with onViewModeChange, and likewise for zoom, fitMode (none, width, page), scoreIndex and staffSize. minZoom, maxZoom and zoomStep bound the zoom buttons and Ctrl-scroll.

Score without chrome

<ScoreView> renders only the pages, for hosts that bring their own controls.

import { ScoreView } from "@viritura/score-viewer-react";

<ScoreView mnx={mnx} viewMode="spread" zoom="fit-width" pageBackground="#fff" />;

It accepts the viewer's layout and presentation options as props: pageWidth, pageHeight, pageMargins, spatium, scoreIndex, viewMode, zoom, gap, spreadFirstPage, pagesPerRow, pageBackground, contentAlign, ink and assetBaseUrl. <ScoreViewer> accepts contentAlign too. Pass bare to remove the viewport padding when embedding a cropped fragment in a tight panel.

Playhead

<ScoreView mnx={mnx}>
  <ScoreView.Playhead beat={beat} partId="flute" follow style={{ color: "#e34935" }} />
</ScoreView>

Pass beat for a global quarter-note beat, or position={{ measureIndex, beat }}. follow keeps the playhead in view. render replaces the default bar with your own element and receives { x, y, height }.

Page overlays

<ScoreView mnx={mnx} pagesPerRow={2}>
  <ScoreView.Page page={0}>
    <span style={{ position: "absolute", top: 8, right: 8 }}>Page 1</span>
  </ScoreView.Page>
</ScoreView>

<ScoreView.Page> is an absolutely positioned container over one page that tracks zoom and arrangement. Use it for badges, comments and annotations. For custom children, useScoreView() returns the engine, display list, zoom, page positions, view mode and the underlying viewer handle.

Loading, errors and callbacks

Prop Notes
loadingFallback Shown while the engine loads or layout runs
errorFallback (error) => ReactNode, shown when loading or layout fails
onReady Called with { engine, displayList } after each layout
onPaint Called after visible pages are painted
onError Called with an EngineLoadError, ParseError or LayoutError

Engine hook

import { useScoreEngine } from "@viritura/score-viewer-react";

function CustomCanvas({ mnx }: { mnx: string }) {
  const { engine, displayList, loading, error } = useScoreEngine(mnx, { pageWidth: 800 });
  if (loading) return <p>Loading score</p>;
  if (error) return <p>{error.message}</p>;
  // paint with engine.paint(ctx, displayList, { page: 0 }) in your own canvas
  return null;
}

useScoreEngine(mnx, layoutOptions, loadOptions) loads the engine and lays out the document whenever the inputs change. Use it when you paint with the Score Engine yourself. The package also re-exports the engine's loadEngine, error classes and types, so one import is enough.

Hosts with rewritten asset URLs

Sandboxed hosts such as VS Code webviews serve files from rewritten URLs. Pass the base URL that contains wasm/ and fonts/:

<ScoreViewer mnx={mnx} assetBaseUrl={webviewAssetBaseUrl} />