ariadne inks by darkness. That single fact decides which photographs work, and it is the thing to reason from when one does not.

A tour can only draw the tonal range the photograph actually spreads across. Everything below is about getting a picture’s tones into a range the renderer can use — before touching --gamma, which is a weight control, not a range control.

Symptom: an even scribble with no figure

The subject and its background share a tone. There is no signal saying where the subject is, so ink lands everywhere.

Measured on one photograph: a brown sweater at luminance 0.271 against a wall at 0.279 — a gap of 0.008. No --gamma, --floor, or point count recovers a figure from that, because the information is not in the image.

Fix: a mask. See Masking a photograph. The mask supplies the figure/ground division the photograph lacks.

a-tsp photo.jpg --hard        # segment, inspect the overlay
a-tsp photo.jpg --hard --go   # render

Symptom: a flat silhouette, filled but unmodelled

The subject is separated, but reads as a solid shape with no interior form.

Its tones are bimodal rather than spread. On one photograph the subject’s median luminance was 0.165 while the 95th percentile was 0.865: 59% of the subject sat below 0.2, all mapping to nearly the same ink, while the lit 16% got almost none. The modelling in between was crushed out.

Gamma cannot fix this. Raising it empties the lit areas further (16% → 23% of the subject below ink 0.1 going from γ2.5 to γ4.0); lowering it floods the darks. You are moving a compressed range around, not expanding it.

Fix: redistribute the range first.

a-equalize photo.jpg masks/photo_mask.png prepared.png --strength 0.6
ariadne --mask masks/photo_mask.png --partition labels --groups 2 \
        -g 2.0 --floor 0.06 -w 1.5 prepared.png

equalize.py equalises by rank within the masked subject, so every tonal band ends up with a similar share of the pixels. The background is untouched, so the mask still separates. --strength 0.6 keeps some of the photograph’s own lighting; 1.0 opens up the most anatomy but flattens the light direction.

Then tune --gamma for weight — second, not first.

Symptom: one bright region drops out of the picture

Part of the subject is so light that it earns no ink and reads as a hole.

This is not a background problem. Darkening --background would give you a dark field with a hole in it; the region has no lines, not insufficient contrast. And note that equalisation makes it worse — an already-bright region gets pushed further toward white:

treatment ink in that region fraction with no ink
original 0.270 42%
--strength 0.6 0.152 52%
--strength 1.0 0.095 62%

Two fixes, with different costs.

Cap the highlights — squeeze the whole subject into [0, 0.75] so nothing reaches paper white. Simple, and it fills the figure completely, but it compresses the midtones where the modelling lives, so the result is flatter.

Per-region tone control — the better answer when the image is worth it. Split the subject into a shadowed region and a lit one, give each its own tonal window, and let each be its own subtour:

shadow = subject & ~lit
out[shadow] = equalise(lum[shadow], 0.6, 0.05, 0.62)   # keep it dark
out[lit]    = equalise(lum[lit],    0.9, 0.30, 0.80)   # pull DOWN to earn ink

Paint the two regions as separate mask colours, then render with one ink each:

ariadne --mask masks/photo_3group.png --partition labels --groups 3 \
        --ink '#f2f4f5,#141414,#5a6068' -n 120000 -g 2.0 --floor 0.03 photo_pertone.png

The lit region ends lighter than the shadowed one, so the light direction survives instead of being flattened. Measured on one photograph, this took the fraction of subject with no ink from 52% to 0% in shadow and 4.8% in the lit region, while keeping the interior modelling the cap approach loses.

The mask sets grouping; the image sets density. That division is the whole technique. Anything you want drawn differently within a group is done by editing a copy of the photograph, not the mask — the same move that makes a metal vessel read against the smoke it sits in.

Provenance

Every generating script writes <output>.meta.yaml beside its output, recording the source, content hashes, tool versions, and the exact commands to rebuild it. Read it when you want to know how a picture was made; re-run its steps in order to remake it.

ariadne is a Rust binary and writes no sidecar of its own, so run it through tools/draw.py when you invoke it directly — it passes every argument through unchanged and records the call. Otherwise the parameters live only in your shell history.