Pointer · effect
PointerTrail
Marks pressed into the paper behind the cursor, spreading as they soak in.
Options
-
paper#fbfaf4 -
css colour
The sheet the marks are pressed into.
-
ink#8d8577 -
css colour
Ink that has soaked in. Most of the trail is this.
-
accent#c44400 -
css colour
Ink that has only just landed, at the head of the trail.
-
marks22 -
2 to 28
How many marks the trail holds. The shader has room for 28; asking for more silently gives you 28, because the array is a fixed size and growing it means editing the shader as well.
-
size0.032 -
0.005 to 0.2
Radius of a fresh mark, as a share of the short side, so it keeps its proportion when the element changes shape.
-
spread1.6 -
0 to 4
How much wider a mark gets by the end of its life. Paper draws ink sideways along its fibres, so an old mark is bigger than a new one. This is the opposite of a particle trail and it is the main thing that makes it read as ink.
-
fade1.8 -
0.2 to 6
How quickly a mark gives up. Higher is a shorter trail with a harder end; lower leaves a long tail that never quite goes.
-
edge0.85 -
0 to 1
How much of a mark is its soft shoulder rather than its body. Ink on a fibrous surface has no edge to speak of, so this wants to be high; at 0 you get discs.
-
spacing0.035 -
0.005 to 0.2
Seconds between one mark and the next when the trail is replayed from a scripted path. It has no effect on a live pointer, where one mark is laid per frame.
-
grain0.4 -
0 to 1
Paper tooth under the marks.
What it needs
- Dependencies
- None at all
- Browser
- WEBGL2
- Frame budget
- ~1.2 ms · 1 context
- Pinned to
- v0.11.0
- An older mark is wider and paler than a new one, because paper draws ink sideways along its fibres while it sinks in. That is the opposite of a particle trail, where older means smaller
- The marks multiply rather than compositing, so two that overlap are darker than either
- A trail needs history, which is not a function of t. When pointerPath is set the whole track is known in advance and the trail is read backwards off it instead of accumulated, so a recorded take is identical however the frames are asked for. A live pointer falls back to a ring buffer
- One WebGL2 context, one full-screen triangle, no buffers and no attributes
- One distance and one smoothstep per mark per pixel, and the loop stops at the number of marks actually held
- The mark positions are a single vec2 array uniform, uploaded once per frame
- Cost scales with the mark count rather than with how far the cursor has moved