Algorithms
Every way this library knows of splitting one image across frames, run on the same content and scored against three different denoisers. Two of them work by different mechanisms, two fail, and the failures are kept so they can be run rather than asserted.
Modulation here is measured per frame boundary and says nothing about how often those boundaries arrive. Aperture needs six frames per cycle where amplitude needs two, so on a 60Hz display its cycle runs at 10Hz against amplitude's 30Hz. Around 8 to 15Hz is where the eye's temporal sensitivity peaks, so aperture puts a smaller modulation at the worst possible rate and amplitude puts a larger one near fusion. Smaller steps, far more visible.
So the comfort axis needs frequency in it, not just amplitude, and until it does these numbers rank configurations only when the frame count is equal. Aperture remains worth having for the case it was built for, a palette with no headroom at all, but it is not the comfortable option and this page should not have said so on one number.
Both axes, on one page
These used to be two pages, which was a mistake: they measure different things about the same object. Leak is what an attacker gets. Modulation is what a viewer pays. Every mode has both, and a mode is only worth shipping if you have looked at both.
Within-pair modulation is the flicker between the two frames of a cycle. It carries the masking and cannot be lowered without lowering the protection. Across-cycle is the flicker between one cycle and the next. It carries nothing, and every code level of it is churn for no security at all.
Leaning the noise toward the ink
Flicker over empty background protects nothing, so ink-bias lets
the amplitude lean toward where the content is. It is the largest comfort win
available and it comes straight out of the protection, because where the
noise is, is where the text is. Measured over 6 seeds on the shipped
palette:
| ink-bias | leak after the best blur | within-pair modulation |
|---|---|---|
| 0, ships | 0.263 | 96.5 |
| 0.2 | 0.304 | 81.4 |
| 0.4 | 0.361 | 66.4 |
| 0.6 | 0.441 | 51.4 |
| 1.0 | 0.732 | 21.4 |
Around 0.2 buys roughly 16% less flicker for a leak still under a third. Past 0.4 the value starts coming back and by 1.0 it is plainly readable, which is the trap arriving exactly as predicted rather than as a surprise.
What the merged page got wrong first
aperture is far calmer than amplitude, and neither page could have told you that on its own. Measured on the panels above at the shipped block:
| mode | leak | within-pair | across-cycle |
|---|---|---|---|
| amplitude | 0.248 | 94.2 | 47.6 |
| aperture | 0.148 | 21.6 | 21.6 |
A quarter of the modulation, and it reads far worse. The number is per frame boundary and aperture has three times as many of them per cycle, so what looks like a calmer field is a smaller step delivered at 10Hz instead of 30Hz. The table above is only comparable between modes with the same frame count, which is a limitation of the measurement rather than a property of the modes.
Note also that aperture has within-pair equal to across-cycle. Its frame content is deterministic rather than redrawn each cycle, so consecutive frames differ by the same amount whether or not a cycle boundary sits between them. amplitude is the only mode here where the two numbers come apart, and that gap is the churn worth attacking.
Two mechanisms, not one
amplitude and aperture hide in genuinely different
ways, and the difference decides which one you want.
amplitude degrades everything. Every pixel is in every frame at the
wrong value. Nothing is missing and nothing is right, and how wrong it can be
depends on how much headroom the colours have. White has none, which is why
fit exists.
aperture withholds most of it. One slice per frame, carried perfectly, the rest genuinely absent from the file. It does not care about colour at all, so it works at pure white where amplitude cannot. The cost is that what it does show, it shows exactly, and a burst of N frames has everything.
So: amplitude against a single screenshot on a palette with room, aperture when the palette has none and you can accept the flicker of a sweeping band.
Why the other two fail
The three that fail all split a dimension the eye does not need in order to
recognise something. Recognition survives losing colour, losing most of the
pixels, blur, and heavy quantisation. What it does not survive is having the
pixel values randomised, which is the one thing amplitude
does and the others do not.
That is worth stating as a rule, because the failures are the tempting ideas. Splitting colour across frames sounds like it should hide something. It hides nothing: one frame is a greyscale copy at full spatial resolution. Splitting pixels across frames sounds stronger still, and gives you a copy at half resolution, which reads fine.
Where the score itself fails
leakScore is the absolute Pearson correlation between one frame
and the truth, and it is a proxy rather than the thing itself. It has a blind
spot worth knowing about, because this page walked straight into it.
A mode that inserts a large pattern unrelated to the content, as
interleave does with its flat fill, gets a better score for
it. The fill adds variance that correlates with nothing, the correlation is
diluted, and the number improves while the frame stays perfectly readable. The
first version of this page reported 0.19 for interleave and called it masked,
next to frames you can read at a glance.
The lesson generalises past this one mode: a metric that disagrees with your eyes is wrong until proven otherwise. The frames are shown above every score on this page for that reason.
About the attacks
Every blur-resistance figure in this project used to be measured against a box blur, which is the cheapest denoiser there is. That is a weaker claim than it sounds, so the stronger ones are here and run on every algorithm.
The box blur wins anyway. At the shipped defaults nothing beats not attacking at all, and the ordering holds in the under-protected case where the block is half the stroke. The scores above are computed live on this page, so read them there rather than here.