Effects and transitions

What the canvas does to the media while the slider moves, while the pointer is over it, and while one slide turns into the next. And how to write one.

Any number, in the order given.

EffectDoesMoves with
stretch( { amount } )The middle of the image hangs backSpeed
split( { amount } )The colours come apartSpeed
parallax( { amount, zoom } )The image is slower than its slide; closer all round, so it keeps its shapePosition
bend( { amount, speed } )The row is an arc; bends the meshPosition and speed
magnify( { size, strength } )A lensPointer
cells( { size, zoom, reach } )Squares in the wake of the pointer, each its part closer; as far as the pointer is fastSpeed of the pointer
spotlight( { size, dim } )The rest is dimmedPointer
reveal( { size } )The images lose their colours, except around the pointerPointer
glass( { size, lines, amount } )Fluted glass around the pointerPointer
pixels( { size, cells } )Coarse pixels around the pointerPointer
tilt( { angle } )The slide leans to the pointer; turns the meshPointer
waves( { size, amount, speed } )Rings run away from the pointer, while it is over the sliderPointer and time
smear( { size, amount } )The pointer drags the image alongSpeed of the pointer
shift( { size, amount } )The colours come apart along the way of the pointerSpeed of the pointer
jelly( { amount, across } )The slides are soft: what moves them pulls them out of shape; bends the meshSpeed
slab( { edge, bend, spread, shine } )The slides are thick glass with a round bevel: the image is refracted through it and its colours come apart there, the rim catches a light at the top left, and a streak of reflection lies on the flatSpeed, a little

Effects that lay out: the slider moves as ever, the effect says where a slide is drawn. For one slide per view or align: 'center'; give the slider padding for what leaves its place.

EffectDoes
coverflow( { angle, depth, range } )The slides beside the active one turn away
pile( { offset, turn } )A pile of cards; the one on top leaves to the side
fan( { angle, radius } )A hand of cards, or a wheel
wave( { height, length, slope } )The row runs along a wave, across the view on a slope
unweave( { amount, threads } )Near the edges of the view the slides come apart into threads
dome( { amount, centre, size } )The slides as on a dome: what is far from the middle is smaller and nearer to it

The page has such a slide in one place, and the canvas draws it in another. A click is a click on the slide that is seen: on the cover at the edge, not on the slide in whose place it is drawn. And the lightbox lets the image grow out of the slide as it is drawn: a cover that is turned away turns to the front while it grows, and turns back on its way home. canvas() sees to that with hit(), which it loads when an effect lays out; with a layer by its name it is a plugin to add:

import { gl, hit, coverflow } from 'gpuslider/gl';

const effects = [ coverflow() ];
createSlider( element, { align: 'center', plugins: [ gl( { effects } ), hit( { effects } ) ] } );

Effects under the pointer (waves(), spotlight(), magnify() and the others) have the pointer where it is on the slide as it is drawn.

slider.plugins.hit.at( x, y ) is the slide that is seen at a point of the page, .where( index ) is what is around a slide as it is drawn. What is there to be used in a slide (links, buttons) is where the page has it.

Transitions, for stack(), one at a time: liquid, ripple, glitch, burn, pixelate, swirl, lens, fluted, warp, zoom, mosaic, blocks, fold, signal, push, chroma, kaleido, displace, datamosh, wind, distance. Without one the stack fades.

createSlider( element, {
	plugins: [ stack(), canvas( { effects: [ split(), burn() ] } ) ],
} );

A page that lets its visitors choose names every transition it offers, with choose(): they are one shader, and pick( i ) changes the one that is drawn from the next move on, without a shader or a slider made again. A page that has one transition names that one, and has no other in its bundle.

import { choose, liquid, burn, push } from 'gpuslider/effects';

const turn = choose( [ liquid(), burn(), push() ] );
createSlider( element, { plugins: [ stack(), canvas( { effects: [ turn ] } ) ] } );
turn.pick( 1 ); // burn

A stack in the first view of a page says so in its HTML: class="gs gs-stack". Then the slides are on top of each other before the script is there, and nothing of the page gives way when it comes. Without the script such a slider shows its first slide, and is no scroller: the slides after the first cannot be reached then. It is for a stack that starts at its first slide.

Your own

An effect is an object of GLSL function bodies. It is written once and runs on both layers: for WebGPU it is translated to WGSL when the shader is made.

const wobble = ( { amount = 0.02 } = {} ) => ( {
	params: { amount },
	animated: true,
	uv: `
	uv.x += sin( uv.y * 20.0 + uTime * 3.0 ) * amount;
	return uv;`,
} );
HookSignature
vertexvec3 ( vec3 p, vec2 uv )Moves the mesh. p in px from the centre of the slide, z towards the viewer
uvvec2 ( vec2 uv )Moves the lookup
colorvec4 ( vec4 color, vec2 uv )Changes the result; may call media( uv )
transitionGLSL with vec4 transition( vec2 uv )Stack only. getFromColor, getToColor, progress: what is written for gl-transitions runs as it is

A parameter is a number, or an array of 1 to 4. An array stays the array it was given: what the page writes into it is drawn in the next frame, which slider.wake() asks for. That is how a page tells an effect what only the page knows: where it is scrolled to, how loud the music is, where the middle of a wall of sliders is.

const level = [ 0 ];
const loud = () => ( {
	params: { level },
	uv: `return ( uv - 0.5 ) * ( 1.0 - 0.1 * level ) + 0.5;`,
} );
// Later, as often as it changes.
level[ 0 ] = 0.8;
slider.wake();

An effect that lays the slides out says in JS too where it moves a point to, so that a click finds the slide that is seen: place( p, about ) does what vertex does, with p as [ x, y, z ] and about with progress, velocity, size, view and quad as the uniforms of their names. Without it a click is a click on the slide whose place on the page it is.

head is GLSL the bodies need, animated: true says that it moves without the slider moving, animated: 'pointer' that it does while the pointer is over the slider.

Uniforms: uProgress, uVelocity, uPointer, uPointerSpeed, uPointerIn, uTime, uSize, uView, uQuad, and in color and uv also uRadius. See src/gl/program.js.

What the translation knows is the GLSL that all effects here are written in. For an effect that is to run on WebGPU too:

  • Functions, if, for, a ? b : c, and the functions GLSL comes with. No out and inout parameters, no structs, no arrays, no #define.
  • What max, min, clamp and smoothstep are given is of one kind: max( v, vec2( 0.0 ) ), not max( v, 0.0 ).
  • One component is assigned at a time, or the whole vector: p = vec3( q, p.z ), not p.xy = q.

A shader that WebGPU does not take is said in the console, as gpuslider: …, and the page draws that slider.