Parts & Layers

Oscilla supports two approaches to per-performer parts: separate score files and stacked layers within a single SVG. Both are configured in the Parts tab of the preferences dialog and stored per-browser, so each performer on a shared network can independently choose their own view.

The two approaches can be combined. A project might use separate score files for radically different parts (e.g. a conductor score and a performer score) while also using layers within each file for finer distinctions (e.g. violin I and violin II sharing a string parts score).


Approach 1: Separate Score Files

Each part is authored as an independent scrolling SVG. All files live in the project root alongside score.svg:

myProject/
├── score.svg                  # full score (always present)
├── score-part-violin.svg      # violin part
├── score-part-viola.svg       # viola part
├── score-part-cello.svg       # cello part
├── score-conductor.svg        # conductor view
├── preferences.json
└── pages/

Naming Convention

Files must match the pattern score*.svg:

The prefix score is required. Everything after it becomes the display label in the preferences dialog. Hyphens become spaces: score-part-violin.svg appears as part violin.

When to Use Separate Files

Separate files are appropriate when parts differ substantially in content, layout, or length:

Authoring

Each file is a standard Inkscape SVG. All the usual cue syntax works identically — cues are embedded in element IDs just as in score.svg. The scrolling playhead, transport, timing, and synchronisation all work the same regardless of which score file is loaded.

One important consideration: if you use cue IDs that reference specific elements (e.g. nav(scroll@A)), the rehearsal marks referenced must exist in the currently loaded score file for that performer. If mark A exists in score.svg but not in score-part-violin.svg, navigation cues targeting it will not work for a performer who has selected the violin part.

Performer Selection

Each performer selects their score file in Preferences > Parts > Score. The selection is stored in the browser's localStorage and takes effect on the next project load. This means each performer on a different device (or browser) can independently choose which score file they see, while all remaining synchronised via the shared transport.


Approach 2: Stacked Layers

A single score.svg contains all parts as Inkscape layers. Each performer can highlight their own layer and dim the others.

Creating Layers in Inkscape

  1. Open score.svg in Inkscape
  2. Open the Layers dialog: Layer > Layers... (or Shift+Ctrl+L)
  3. Create a layer for each part, naming it with "part" in the name
  4. Draw each instrument's notation on its own layer
  5. Put shared elements (barlines, rehearsal marks, time signatures, background) on a layer without "part" in the name
  6. Save

Each layer corresponds to a <g> element in the SVG with Inkscape's layer attributes:

<g inkscape:groupmode="layer"
   inkscape:label="Part: Violin"
   id="layer1">
  <!-- score content for violin -->
</g>

Naming Convention

Oscilla scans Inkscape layers (groups with inkscape:groupmode="layer") and includes only those whose label contains the word part (case-insensitive). Layers without "part" in their name are never filtered, making them suitable for shared notation, grids, or background elements.

This means names like "Part 1 Violin", "viola part", or "PART: Electronics" are all detected, while layers named "Background", "Grid", or "Shared" are excluded and remain fully visible regardless of the performer's selection.

Layer Name Filterable? Why
part-violin Yes contains "part"
part-cello Yes contains "part"
conductor-part Yes contains "part"
shared-notation No no "part" in name
background No no "part" in name
grid No no "part" in name

When to Use Layers

Layers work well when parts share the same horizontal timeline and general layout but differ in vertical content:

Preferences UI

The "Parts" section appears automatically in the Preferences dialog when a score contains Inkscape layers with "part" in their name. It provides two controls:

Control Description
My Part Dropdown listing all detected layers, plus "All (no filter)"
Other Parts Opacity slider (0–100%) for non-selected layers

Changes apply immediately as a live preview. The setting is also saved when the Preferences dialog Save button is pressed.

Behaviour

Storage

Layer filter preferences are stored in localStorage, keyed per project:

oscilla_layerFilter_<projectName>

This means each browser or device maintains its own part selection. A violinist's tablet remembers "Part: Violin" while the cellist's tablet remembers "Part: Cello", even when viewing the same score. The preference is not saved to preferences.json on the server and does not affect other connected clients.


Combining Both Approaches

A project can use both methods simultaneously. For example:

myProject/
├── score.svg                  # full score with all layers
│   ├── [layer] part-violin-I
│   ├── [layer] part-violin-II
│   ├── [layer] part-viola
│   └── [layer] shared
├── score-part-cello.svg       # cello has its own score entirely
├── score-conductor.svg        # conductor view with annotations
└── preferences.json

Here the string players share a layered score (each highlighting their own part), while the cellist and conductor each have dedicated score files.

The Parts tab in preferences adapts to what is available: if multiple score files exist, it shows the Score dropdown. If the currently loaded score contains layers with "part" in the name, it shows the layer filter controls. If both are present, both controls appear.


View Modes

The Default View setting in Preferences > Settings interacts with parts:

Mode Behaviour
hybrid (default) Loads the selected score file for scrolling. Page navigation also available via cues or the mode toggle.
scroll Same as hybrid. Score file is required.
page Starts in page mode. If a score file exists, the mode toggle allows switching to scroll view. If no score*.svg files exist, pure page mode with no scroll option.

In hybrid and scroll modes, the selected score file determines what scrolls. In page mode, score file selection is irrelevant unless the performer switches to scroll view.


Authoring Tips


Project Structure Summary

myProject/
├── score.svg                  # main scrolling score (required for scroll/hybrid)
├── score-part-*.svg           # optional per-performer score files
├── preferences.json           # project settings
├── pages/                     # page-mode SVGs (optional)
│   ├── home.svg
│   └── section-a.svg
├── audio/                     # audio files (optional)
├── text/                      # text cue content (optional)
└── video/                     # video files (optional)

Quick Reference

What you want What to do
Different notation per instrument Create separate score-part-*.svg files
Same notation, highlight own part Use Inkscape layers with "part" in the name
Both Combine: layers inside score files, plus separate files for very different parts
Shared elements visible to all Put them on a layer without "part" in the name
Performer chooses their part Each performer opens Preferences > Parts
Settings persist across sessions Automatic — stored in browser localStorage
Settings sync across devices They do not — each browser has its own selection, which is the intended behaviour

Technical Details

The layer filter is implemented in layerFilter.js with integration points in projectLoader.js (layer scanning on score load) and oscillaPreferences.js (UI section in preferences dialog).

Layer detection uses both namespace-aware attribute access (getAttributeNS) and a plain attribute fallback (getAttribute("inkscape:groupmode")) to handle differences in how browsers resolve XML namespaces when SVG is embedded in an HTML document.

Tip: use ← → or ↑ ↓ to navigate the docs