image(...) — pictures in a score
A picture drawn straight into the SVG is fine when it never changes. image()
is for when it does: a folder of plates dealt out in a different order each
performance, a slideshow that advances while the playhead is inside a region, a
picture chosen by the same kind of pattern that chooses a sound.
image(src:cloud.png) one file, shown when triggered
image(path:plates, mode:shuffle) a folder, a different one each pass
image(src:Pseq(a.png, b.png, inf)) an explicit order
image(path:plates, mode:seq, dur:2) a slideshow, two seconds a frame
Where the pictures live
In the project's images/ folder, beside audio/ and video/:
myScore/
├── score.svg
└── images/
├── cover.png
└── plates/
├── plate-01.png
├── plate-02.png
└── plate-03.png
path:plates takes everything in that subfolder. PNG, JPEG, GIF, WebP, AVIF,
SVG and BMP are recognised. Files are fetched ahead of time, so the picture is
ready before the playhead reaches it.
The element is the frame
The cue goes on an ordinary SVG element — usually a rectangle you draw in Inkscape where the picture should appear. Its box is the frame: the picture is placed there and sized to it, and the rectangle itself is hidden once the picture is in. Move or resize the rectangle and the picture follows.
<rect id="plates" data-oscilla="image(path:plates, mode:shuffle)"
x="4200" y="180" width="900" height="600"/>
Parameters
| Key | Default | Description |
|---|---|---|
src |
— | One file, or a pattern of files: Pseq, Prand, Pxrand, Pshuf, Pchoose |
path |
— | A folder inside images/. Every picture in it becomes the pool |
glob |
— | Filter the folder, * and ? wildcards: glob:plate-*.png |
mode |
shuffle |
Which one next, see below |
fit |
contain |
contain shows the whole picture letterboxed, cover fills the box and crops, fill stretches |
dur |
— | Seconds per picture. Without it, one picture per trigger; with it, a slideshow |
fade |
0 |
Fade in and out, in seconds. fadein / fadeout set them separately |
opacity |
1 |
0 to 1 |
uid |
element id | Cues sharing a uid share a position in the folder, so two frames can deal from one pack |
trig |
playhead |
As for any cue: playhead, click, auto, or another object's uid |
Before it is triggered
By default the box shows the first picture of whatever it is pointed at, so a score at rest reads as the score rather than a row of empty rectangles. The real sequence replaces it when the cue fires.
image(path:horse) first frame showing until triggered
image(path:horse, placeholder:0.35) the same, dimmed to mark it "not yet"
image(path:horse, placeholder:0) an empty box until the playhead arrives
Fullscreen cues are never given a placeholder — one covering the window before its time would be worse than an empty box.
Scrubbing back
Move the playhead back to before a trig:playhead image cue and it stops: the
slideshow ends, the folder starts again from the top, and the placeholder comes
back. The score returns to how it looked before that cue had played, which is
what rewinding past something ought to mean. Cues driven by a hand
(trig:click) or by another object are left alone.
Fullscreen
size:fullscreen puts the picture over the whole window instead of inside a box
in the score. The score keeps scrolling underneath, so the playhead does not lose
its place while the picture is up.
image(src:plate.jpg, size:fullscreen, close:1, fade:0.4)
image(path:plates, size:fullscreen, dur:3, hold:30, backdrop:1)
image(src:ground.jpg, size:fullscreen, layer:under, opacity:0.4)
| Key | Default | Description |
|---|---|---|
size |
— | fullscreen (or fs) for the whole window |
layer |
over |
over the score, or under it — a ground the notation is read against |
backdrop |
1 |
Dim the score behind the picture. backdrop:0 leaves it visible |
close |
0 |
A close button in the corner |
clickclose |
0 |
Click the picture itself to dismiss it |
hold |
— | Seconds up, then it goes by itself |
Getting out again, in order of how deliberate they are: hold: takes it away
on a timer, close:1 gives a button, clickclose:1 lets a press anywhere on the
picture dismiss it, and Escape always works — a fullscreen picture is the
first thing Escape backs out of, one press per picture, the same as a fullscreen
video.
dur: and hold: do different jobs and combine: dur: is the step of a
slideshow, hold: is how long the whole thing stays. image(path:plates, size:fullscreen, dur:2, hold:20) deals a new plate every two seconds and gives
up after twenty.
Layering follows the video cue: backdrop, picture, close button in that order,
above the score. layer:under drops the picture beneath the notation instead.
Modes
shuffle— a fresh random order each time through the folder, so nothing repeats until everything has been seen. The usual choice.seq— in order, wrapping round at the end.random— chosen independently every time, so repeats happen.once— through the folder once, then nothing further.
Sharing a pack between frames
Two cues with the same uid draw from one pool and one cursor, so three frames
on a page can show three different pictures from the same folder rather than
three copies of the same one:
image(path:plates, uid:pack, mode:shuffle)
image(path:plates, uid:pack, mode:shuffle)
image(path:plates, uid:pack, mode:shuffle)
Examples
// a cover that appears once and stays
image(src:cover.png, fit:cover, fade:1)
// a new plate at every rehearsal mark, never repeating within a pass
image(path:plates, mode:shuffle, fade:0.3)
// a slideshow while the playhead is in this region
image(path:film, mode:seq, dur:0.5)
// performer-triggered
image(path:plates, mode:random, trig:click)
// fired by another object crossing it
image(path:plates, trig:readPH)
Opacity from another object
opacity takes a follow(), so anything publishing a 0-1 signal can dim the
picture live:
image(uid:plate, src:horse.jpg, opacity: follow(fader.t))
The two cues know nothing about each other — the fader publishes fader.t, the
image follows it. Any 0-1 source works: an o2p() dot's travel along its path
(follow(dot.t)), a controlXY handle (follow(pad.y)), mic amplitude
(follow(adc.amp)), or an incoming OSC address (follow(/pedal/1)).
In a sequence the binding follows the pictures: each new frame is placed at the current value rather than at the one written in the score.
Picking the plate with a signal
A folder is normally dealt out — mode:seq steps through it, mode:shuffle
reorders it. index: turns it into a lookup table instead: something else
chooses which plate is showing.
image(uid:plate, path:horse, index: follow(dial.t))
With no range, follow() spans the whole folder: 0 is the first file, 1 the
last. Give numbers to use part of it — follow(dial.t, 3, 8) scrubs the middle
six plates only. Values are rounded to the nearest file and clamped, so a
source that overshoots holds at an end rather than going blank.
While index: is bound, dur: is ignored — something else is doing the
advancing. Reloading the same plate is skipped, so a slow-moving source does
not thrash the image element.
This is how you scrub a frame sequence by hand, or drive it from anything that
moves: a rotate()'s angle, a trans() bar's progress, a controlXY handle,
an incoming OSC pedal.
What an image publishes
An image() reports which plate it is on, so the pictures can drive something
else in turn:
| Channel | Meaning |
|---|---|
index |
which file, 0-based within the folder |
t |
the same position as 0–1 |
image(uid:plate, path:horse, mode:seq, dur:0.12)
synth(uid:s1, wave:sine, freq: follow(plate.t, 200, 900), amp:0.1)
A src: pattern of explicit filenames has no folder to be a position in, so it
publishes nothing — only a path: folder (or a file list) has an index.
Demo
See demo-image — pictures from a file, a folder and a pattern, using Muybridge's galloping horse.
http://localhost:8001/?project=demo-image
Tip: use ← → or ↑ ↓ to navigate the docs