diff --git a/docs/manual/README.md b/docs/manual/README.md
index 429ed96..d8fa1b1 100644
--- a/docs/manual/README.md
+++ b/docs/manual/README.md
@@ -273,13 +273,16 @@ sensor does not. The list opens over the column and scrolls on its own — by
wheel, drag or flick, or with `Up`, `Down` and `Enter` — down to the
black-and-white stocks at its end.
+
+
The film's sliders work on a mask as they do on the whole photograph, the way
-a printer dodges and burns: in a layer, `Print exposure` darkens or lightens
+a printer dodges and burns: in a layer, `Print Exposure` darkens or lightens
that region of the print, `Push` develops it further, and the stock stays the
one the photograph was made on. Where layers overlap, the photograph takes the
-average of what they ask for.
+average of what they ask for. Below, a negative stock on an alpine frame, then
+a gradient over the sky whose `Print Exposure` burns it in.
-
+
### History, snapshots, presets
diff --git a/docs/manual/index.html b/docs/manual/index.html
index 617db0f..2c4f4bb 100644
--- a/docs/manual/index.html
+++ b/docs/manual/index.html
@@ -332,12 +332,14 @@ named stock; below it, the print exposure and push controls a film has and a
sensor does not. The list opens over the column and scrolls on its own — by
wheel, drag or flick, or with Up, Down and Enter — down to the
black-and-white stocks at its end.

The film's sliders work on a mask as they do on the whole photograph, the way
-a printer dodges and burns: in a layer, Print exposure darkens or lightens
+a printer dodges and burns: in a layer, Print Exposure darkens or lightens
that region of the print, Push develops it further, and the stock stays the
one the photograph was made on. Where layers overlap, the photograph takes the
-average of what they ask for.

Print Exposure burns it in.
+
Every change is a step; Undo and the History panel walk them. Snapshot
keeps the current state under a name. Presets… saves the settings to
diff --git a/docs/manual/media/film-local.gif b/docs/manual/media/film-local.gif
new file mode 100644
index 0000000..a020b93
--- /dev/null
+++ b/docs/manual/media/film-local.gif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6385b8746474faca6467b31a812e1b0db8987ba25c76f82ff5e0e6a846f35c07
+size 2052473
diff --git a/tools/manual/scenes.py b/tools/manual/scenes.py
index 9e90f30..c8bad43 100755
--- a/tools/manual/scenes.py
+++ b/tools/manual/scenes.py
@@ -57,6 +57,7 @@ TEAPOT = '_MG_4918'
PANO_FIRST, PANO_LAST = '_MG_8320', '_MG_8331'
NY_FIRST, NY_LAST = '_MG_8393', '_MG_8397'
ALPS_ROW = ['_MG_8322', '_MG_8328'] # the second row of the alps, first and last
+ALPS_SKY = '_MG_8330' # an upright alpine frame, its top third sky and cloud
TOWER = '_MG_8693' # towers shot looking up: verticals that converge
ROAD = '_MG_8672' # a road under a sky, with marks on it: masks and repair
ROAD_MARK = (0.305, 0.794) # a dark mark on its tarmac
@@ -1005,6 +1006,64 @@ def film():
undo_all()
+FILM_LOCAL = 'Kodak Ektar 100' # a negative, so it is printed and has a print exposure
+
+
+def choose_film(stock):
+ """`stock` chosen from the film list, which is open at its top."""
+ px, py, _, _ = film_list_origin()
+ vx0, vy0, vx1, vy1 = dr.rect(f'{stock}@Text')
+ dr.click(px + (vx0 + vx1) // 2, py + (vy0 + vy1) // 2)
+ pause(3)
+
+
+def gradient_over_top(to_fy):
+ """The linear gradient just added, turned to fall from the top of the
+ frame and its middle moved to `to_fy`. A new one is laid across the
+ middle facing right, its rotate handle below the centre: that handle,
+ dragged round to the right, turns it a quarter to face up."""
+ cx, cy = dr.photo(0.5, 0.5)
+ handles = [(int(h['x'] + h['w'] / 2), int(h['y'] + h['h'] / 2))
+ for h in dr.matches('id:GradientHandles::drag')]
+ rx, ry = max(handles, key=lambda p: p[1])
+ dr.drag(rx, ry, cx + (ry - cy), cy, 25)
+ pause(1.0)
+ dr.drag(cx, cy, *dr.photo(0.5, to_fy), 25)
+ pause(1.2)
+
+
+@scene(media=['film-local.gif'], sources=MASK_SRC + ['core/dr-film/src/**', 'core/dr-pipeline/src/ops/film_sim.rs'])
+def film_local():
+ """A negative stock on the whole photograph, then a gradient over the
+ sky whose Print Exposure burns it in, as a printer would under the
+ enlarger, the mask drawn as its edge so the print shows through; Done
+ Masking, then Before held."""
+ at_develop(ALPS_SKY)
+ in_column('Film@Button')
+ film_list_open()
+ choose_film(FILM_LOCAL)
+ tool('Local')
+ rec('film-local')
+ pause(0.6)
+ dr.click(*in_column('Linear@Button'))
+ pause(1.5)
+ gradient_over_top(0.36)
+ dr.click(*in_column('Edge@RadioButton')) # an outline, so the tint hides nothing
+ pause(1.2)
+ slide('Print Exposure', 28, 30)
+ pause(2.0)
+ dr.click_on('Done Masking@Button')
+ pause(2.0)
+ hold_before(1.6)
+ pause(1.0)
+ cut()
+ tool('Local') # masks shown tinted again, as the other scenes
+ dr.click(*in_column('Tint@RadioButton')) # expect; offered while one exists
+ pause(0.6)
+ tool('Photo')
+ undo_all()
+
+
FILM_LAST = 'Ilford HP5 Plus' # the last stock `DevelopSession::film_choices` lists
FILM_ROWS = 28 # None and the 27 camera stocks
FILM_ROW, FILM_LIST_MAX = 32, 320