API Reference

Powerpoint-like transitions implemented in VapourSynth.

All transitions, unless explicitly stated, start with a pure frame from clipa, or generally the first clip. The transition ends with a pure frame from clipb, or generally the second clip. If specified, the transition will be frames long. If not given (or given 0), the transition will be the entire length of the shortest clip given. The frames parameter cannot excede the number of frames in either clip.

All transitions, unless explicitly stated, consume frames from both clips in the same way. As the transition progresses, frames from the end of the first clip and from the start of the second clip are consumed simultaneously. Frame 0 of the transition, although purely clipa, consumes the first frame from clipb.

As an example, two 5-frame clips are faded, with the frame numbers for clipa on the left, and for clipb on the right.

_images/example_consume_frames.gif

The next example starts with a 15-frame long black clip, and a 10-frame long white clip. The transition lasts 4 frames. (Frames 12, 13, 14, 15 from the first clip are consumed concurrently with frames 1, 2, 3, 4 from the second clip). Notice how only frames 13 and 14 seem to be involved in the transition, as the first and last frames are pure frames from their respective clip.

_images/example_consume_frames_long.gif

For a 24-fps clip, specifying frames=24 will make the transition last a full second. However, since the first and last frame of the transition are purely from clipa / clipb respectively, frames=26 will give a visually one second long transition.

Enums and Constants

class vs_transitions.Direction[source]

Direction enumeration.

Members can be simply referenced by their names, i.e. vs_transitions.LEFT instead of vs_transitions.Direction.LEFT.

DOWN = 'down'
HORIZONTAL = 'horizontal'
LEFT = 'left'
RIGHT = 'right'
UP = 'up'
VERTICAL = 'vertical'
class vs_transitions.MiscConstants[source]

Miscellanious enumeration for some functions.

Members can be simply referenced by their names, i.e. vs_transitions.SLIDE instead of vs_transitions.MiscConstants.SLIDE.

EXPAND = 'expand'
SLIDE = 'slide'
SQUEEZE = 'squeeze'

Non-directional Transitions

Linear Transitions

vs_transitions.fade(clipa, clipb, frames=None)[source]

Cross-fade clips.

fade(hero[:96], dweebs[:96], frames=48).set_output()
_images/fade.gif
vs_transitions.fade_to_black(src_clip, frames=None)[source]

Simple convenience function to fade() a clip to black.

frames will be the number of frames consumed from the end of the src_clip during the transition. The first frame of the transition will be the first frame of the src_clip, while the last frame of the transition will be a pure black frame.

If frames is not given, will fade to black over the entire duration of the src_clip.

fade_to_black(dweebs[:96], frames=36).set_output()
_images/fade_to_black.gif
vs_transitions.fade_from_black(src_clip, frames=None)[source]

Simple convenience function to fade() a clip into view from black.

frames will be the number of frames consumed from the start of the src_clip during the transition. The first frame of the transition will be a pure black frame, while the last frame of the transition will be the last frame of the src_clip.

If frames is not given, will fade in over the entire duration of the src_clip.

fade_from_black(dweebs[:96], frames=36).set_output()
_images/fade_from_black.gif
vs_transitions.pixellate(clipa, clipb, frames=None, lowest_target_w=2, lowest_target_h=2)[source]

Pixellate using rescales and aggressively fade at the center.

For large clips (width x height), the effect might not be too noticeable until the transition is near the middle point. This is due to bicubic downscales and point re-upscales at very high percentages of the original dimensions not being noticeably different.

Due to the way pixellation progress is calculated, the transition must be at least 4 frames long.

Longer transitions paired with larger target dimensions will cause the pixellation effect to appear to pause towards the center of the transition.

Parameters
  • lowest_target_w (Optional[int]) – An integer that determines the minimum width target to downscale to. By specifying None, or by specifying the width of the source clips, the clips will not be scaled in the x or width direction, making this only pixellate vertically.

  • lowest_target_h (Optional[int]) – An integer that determines the minimum height target to downscale to. By specifying None, or by specifying the height of the source clips, the clips will not be scaled in the y or height direction, making this only pixellate horizontally.

pixellate(hero[:84], dweebs[:84], frames=36).set_output()
_images/pixellate.gif

Note

It’s recommended that you keep the pixellation effect limited to about 2 seconds long. Any longer than that and the transition will yield unwanted effects towards the middle point. Changing the target downscale dimensions is also not recommended. Using None or the source clip dimensions will yield interesting but generally terrible results.


Non-linear Transitions

vs_transitions.poly_fade(clipa, clipb, frames=None, exponent=1)[source]

Cross-fade clips according to a curve.

Parameters

exponent (int) –

An integer in the range from 1-5 (inclusive) where 1 represents a parabolic curve, 2 represents a quartic curve, and higher powers more resembling an tight ease-in-out function with constant speed for most of the transition.

An exponent of 1 is probably most useful, as higher exponents tend towards a constant speed and therefore are almost indistinguishable from a normal fade().

red = core.std.BlankClip(format=vs.RGB24, color=[255, 0, 0], length=96, width=320, height=40)
blue = core.std.BlankClip(format=vs.RGB24, color=[0, 0, 255], length=96, width=320, height=40)
div = core.std.Merge(red, blue, weight=0.5).resize.Point(height=2)

normal_fade = fade(blue, red, 96) + fade(red, blue, 96)

poly1 = poly_fade(blue, red, 96) + poly_fade(red, blue, 96)

poly2 = poly_fade(blue, red, 96, exponent=2) + poly_fade(red, blue, 96, exponent=2)

poly5 = poly_fade(blue, red, 96, exponent=5) + poly_fade(red, blue, 96, exponent=5)

core.std.StackVertical([normal_fade, div, poly1, div, poly2, div, poly5]).set_output()
_images/poly_fade_diff.gif

Directional Transitions

Simple Transitions

vs_transitions.wipe(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>)[source]

A moving directional fade.

Similar to a fade(), but with a moving mask. The direction will be the direction the fade progresses towards. (i.e. the second clip begins fading in from the opposite given direction, and the first clip begins fading out starting from the opposite given direction, progressing towards direction)

Uses a pure white to black gradient for the fade. If possible, uses numpy to generate the mask. If the numpy module is not found, falls back to a slower and possibly less accurate approach using lists and the ctypes module for writing to a VapourSynth frame.

wipe(hero[:84], dweebs[:84], frames=60).set_output()

Warning

This is broken (vs/zimg bug with full/limited range grayscale clips as of vs R52 // zimg 3.0)

vs_transitions.linear_boundary(clipa, clipb, clipa_movement, clipb_movement, frames=None, direction=<Direction.LEFT: 'left'>)[source]

Generalized boundary moving function for a linear transition between two stacked clips.

clipa can either slide out of view (having its size unchanged) or be squeezed to nothing from its original size. clipb can either slide into view (having its size unchanged) or be expanded from nothing to its full size. The boundary between the two clips moves towards direction.

The parameter clipa_movement can be MiscConstants.SLIDE or MiscConstants.SQUEEZE. The parameter clipb_movement can be MiscConstants.SLIDE or MiscConstants.EXPAND.

See push(), slide_expand(), squeeze_slide(), or squeeze_expand() for simpler aliases in the same form as most other linear, directional transitions.

vs_transitions.push(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>)[source]

Second clip pushes first clip off of the screen.

The first clip moves off of the screen moving towards the given direction.

Alias for linear_boundary() with clipa_movement=SLIDE and clipb_movement=SLIDE.

push(hero[:84], dweebs[:84], frames=60).set_output()
_images/push.gif
vs_transitions.slide_expand(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>)[source]

First clip slides out of view, while second clip expands into view from nothing.

clipa slides off of the screen towards direction. clipb expands into view from the opposite side of the given direction.

Alias for linear_boundary() with clipa_movement=SLIDE and clipb_movement=EXPAND.

slide_expand(hero[:96], dweebs[:96], frames=84).set_output()
_images/slide_expand.gif
vs_transitions.squeeze_slide(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>)[source]

First clip squeezes into nothing, while second clip slides into view.

clipa gets compressed off of the screen towards direction. clipb slides into view from the opposite side of the given direction.

Alias for linear_boundary() with clipa_movement=SQUEEZE and clipb_movement=SLIDE.

squeeze_slide(hero[:96], dweebs[:96], frames=84).set_output()
_images/squeeze_slide.gif
vs_transitions.squeeze_expand(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>)[source]

First clip squeezes into nothing, while second clip expands into view from nothing.

clipa gets compressed off of the screen towards direction. clipb expands into view from the opposite side of the given direction.

Alias for linear_boundary() with clipa_movement=SQUEEZE and clipb_movement=EXPAND.

squeeze_expand(hero[:96], dweebs[:96], frames=84).set_output()
_images/squeeze_expand.gif
vs_transitions.cube_rotate(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>, exaggeration=0)[source]

Mimics a cube face rotation by adjusting the speed at which the squeeze_expand() boundary moves.

Cube face containing clipa rotates away from the viewer in projected 3-D space towards direction.

Parameters

exaggeration (int) – An integer between 0 and 100 (inclusive) representing how much the effect of the cosine wave should be exaggerated. 0 corresponds to a mathematically correct projection of a 90 degree rotation offset by 45 degrees. 100 corresponds to a fitted cosine wave.

For an explanation for the exaggeration effect, see the following video. The green (circle) is moving with an exaggeration of 0, representing a 2-D projection of the rotating cube face. The blue (cross) is moving with an exaggeration of 100, which is simply just a cosine wave.

For an exaggeration of 0, the initial and final velocities are pi/4 (0.785x), and the velocity at the middle is pi / (2 * sqrt2) (1.11x) (relative to the linear transition).

For an exaggeration of 100, the initial and final velocities are 0, and the velocity at the middle is pi/2 (1.571x) (relative to the linear transition).

_images/cube_rotate_expl.gif
cube_rotate(hero[:96], dweebs[:96], frames=84).set_output()
_images/cube_rotate0.gif
cube_rotate(hero[:96], dweebs[:96], frames=84, exaggeration=100).set_output()
_images/cube_rotate100.gif
vs_transitions.cover(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>)[source]

Second clip slides in and covers the first clip which stays in place.

clipb slides into frame towards direction covering clipa.

cover(hero[:84], dweebs[:84]).set_output()
_images/cover.gif
vs_transitions.reveal(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>)[source]

First clip slides out of view exposing second clip that stays in place.

clipa slides out of frame towards direction revealing clipb.

reveal(hero[:84], dweebs[:84]).set_output()
_images/reveal.gif
vs_transitions.curtain_cover(clipa, clipb, frames=None, axis=<Direction.HORIZONTAL: 'horizontal'>)[source]

Second clip comes into view from both directions split along the given axis covering the first clip in place.

clipb splits and moves inwards along the given axis.

If axis is given as Direction.HORIZONTAL, the clips must have an even integer width. If axis is given as Direction.VERTICAL, the clips must have an even integer height.

curtain_cover(hero[:84], dweebs[:84]).set_output()
_images/curtain_cover.gif
vs_transitions.curtain_reveal(clipa, clipb, frames=None, axis=<Direction.HORIZONTAL: 'horizontal'>)[source]

First clip splits apart to reveal the second clip in place.

clipa splits and moves apart along the given axis.

If axis is given as Direction.HORIZONTAL, the clips must have an even integer width. If axis is given as Direction.VERTICAL, the clips must have an even integer height.

curtain_reveal(hero[:84], dweebs[:84]).set_output()
_images/curtain_reveal.gif
vs_transitions.peel(clipa, clipb, frames=None, direction=<Direction.LEFT: 'left'>)[source]

First clip peels away revealing the second clip beneath.

Both clips remain in place during the transition. The boundary between clips moves towards direction.

peel(hero[:84], dweebs[:84], frames=56).set_output()
_images/peel.gif