page(...) — navigate pages or scrolling positions in the score
Triggers navigation between SVG score pages or scroll positions.
The cue can load a single page, sequence multiple pages, loop sections,
choose randomly from options, randomize order, or define composite playlists
using pattern-based syntax. It forms the structural backbone for cue-based
navigation and timeline control in Oscilla scores.
Syntax
page(
Arguments
| Argument | Description |
|---|---|
| page | ID of a single page or scroll section to load |
| Pseq | sequential playback of listed pages or subpatterns |
| Prand | random selection with replacement |
| Pxrand | random order, reshuffled each repeat cycle |
| Pshuf | random order, shuffled once and repeated as fixed order |
| Pchoose | choose one random page from a list (per trigger) |
| repeats | number of cycles for the pattern (inf = infinite) |
| : |
optional duration for each page (in seconds) |
| after: | optional post-action (e.g. mode(scroll@F)) |
| mode: | switch playback display mode (scroll or page) |
| @uid | rehearsal mark or cue ID to jump to after sequence completes |
Behavior
page(page1)jumps immediately to the given page or scroll position.page(Pseq([page1:2,page2:2],3))loops between pages 1 and 2 three times.page(Prand([page1,page2,page3],5))selects five random pages with replacement.page(Pshuf([page1,page2,page3],2))shuffles once and repeats the same order twice.page(Pxrand([page1,page2,page3],2))reshuffles the list for each repetition.page(Pchoose([page1,page2,page3]))chooses one random page each time the cue is triggered.- Durations can be specified using
pageId:seconds(e.g.page1:5). - The
after:clause defines what happens when the sequence ends (e.g. returning to scroll mode). after:mode(scroll@F)jumps to scroll mode at rehearsal mark F and resumes playback.after:mode(scrollPaused@F)jumps to scroll mode at mark F and stays paused.- All navigation is synchronized across connected clients.
Examples
page(page1) page(Pseq([page1:2,page2:2],3)) page(Prand([page1,page2,page3],4)) page(Pxrand([pageA,pageB,pageC],2)) page(Pshuf([pageIntro,pageMid,pageEnd],1)) page(Pchoose([pageA,pageB,pageC])) page(Pseq([page1:3],1), after:mode(scroll@F)) page(Pseq([page1:3],1), after:mode(scrollPaused@F)) page(Pseq([Pseq([page1:2,page2:2],2),page3:4],1))
Notes
- Pattern parentheses
()are required for lists and sequences. - Repetition counts follow the pattern syntax (
Pseq([...],<count>)). - Durations follow the page name with a colon (
page1:4= 4 s). - The
@suffix defines a rehearsal mark or cue ID to jump to after completion. PshufandPxrandfollow SuperCollider semantics:- Pshuf: shuffled once, same order repeated.
- Pxrand: reshuffled on each repeat.
after:supportsscrollandscrollPausedmodes.scrollPausedkeeps the score paused after return;scrollresumes playback.- Pages without a duration (
page(myPage)or Pseq items without:N) show indefinitely. The sequence waits until the user navigates away — for example by clicking abutton(trigger:nav(scrollPaused@X))inside the page SVG. This is the correct pattern for manually-navigated page networks. - The
@targetinafter:mode(scroll@X)accepts any SVG element id as well as rehearsal marks (resolution order: rehearsal marks → user drop-markers → any element id). - All page and mode changes are fully synchronized across connected clients.
Triggering page() on click
page() cues in a score element's id are playhead-triggered by default.
To trigger a page sequence on click, wrap it in button():
button(trigger:page(Pseq([p1, p2, p3], 1), after:mode(scrollPaused@here)))
Where here is the id of any SVG element in the scroll score that marks
the desired return position.
Creating pages
Pages are plain SVG files in the project's pages/ folder, one page per
file, referenced by file name without the extension: page(intro) shows
pages/intro.svg.
Menu → File → New Page… generates one for you. It is created at the
size of the project's existing pages (or 1366×1024 when there are none, the
size the template's home.svg uses), carries a faint label with its name
and file path, and is shown straight away — press Esc to return to the
score. Draw on it in Inkscape, or keep it as a blank slate. Names take
letters, digits, _ and -; cue keywords such as fade, text or
notation are refused because page(fade) would not parse.
Projects with pages get a dropdown in the top bar listing them — with
scrolling score at the top when there is a score.svg — showing what is
on screen and switching on selection; the hamburger menu's Pages entry
lists the same. The address carries ?page=<name> while a page is shown, so
a browser reload lands back on it, and a page saved from Inkscape while on
screen is remounted in place within a couple of seconds, the way score.svg
already reloads. Esc returns to the score.
The same endpoint is available to scripts:
POST /api/project/<project>/new-page with an optional JSON body
{ "name": "intro", "width": 1920, "height": 1080 } (or "from": "pageA"
to copy that page's size); GET /api/project/<project>/pages lists what
exists and suggests the next free pageN name.
Demo project
See demo-page. It opens in page mode — defaultViewMode:page and defaultPage:home in its preferences.json — on a home page whose buttons open other pages, and whose scrolling examples button (button(trigger:nav(scroll))) is the only way into the scrolling score: a timed page, a Pseq of three pages, a Prand returning paused, a click-to-open button, and pages that carry their own cues. A project never has to touch the scrolling paradigm at all.
http://localhost:8001/?project=demo-page
One view for the whole room
Page navigation is a room event. Whatever changes the view on one client happens on every connected client at the same moment:
- a
page()cue the playhead crosses, or abutton(trigger:page(…))clicked in the score or inside a page; - a
nav(scroll)/nav(scrollPaused@mark)out of a page, from a button or a pattern'safter:; - the page picker in the top bar, Escape, a pedal page-turn, and a click on a page's countdown to skip it.
The client where it happened tells the server, which relays it to the others; they run the same thing without announcing it again. A timed sequence counts down on the shared server clock from the instant it was triggered, and a random pattern (Prand, Pshuf, Pxrand, Pchoose) is drawn once, by the client that triggered it, so every client shows the same page and turns it at the same moment; a click on the countdown skips ahead for everyone.
On your own. A performer can step out of the ensemble's sequence without moving anyone else: shift-click or press and hold the countdown (or Shift+PageDown on a pedal keyboard) skips ahead for that client only, with a fresh random draw from there on, and Shift+PageUp leaves the page for that client only. From then on the ensemble's skips pass that client by until the next page cue. Opening a page pauses the transport for everyone, which is why a page crossed by the playhead has to be shared at all: a client a few units behind would otherwise be left on the stopped score. A page opened from the URL (?page=…) is a personal view and stays local.
Tip: use ← → or ↑ ↓ to navigate the docs