{
  "name": "Tilt (Rotate In)",
  "type": "fixed-intro",
  "duration": 3.0,
  "passes": [
    {
      "name": "rotate in",
      "inputs": [
        "default"
      ],
      "glsl": "precision highp float;

               varying vec2 textureCoordinate;
               varying vec2 sourceTextureCoordinate;

               uniform vec2 outputSize; // size of the output fbo

               uniform float progress; // normalized 0-1

               const vec2 K0 = vec2(502.0 / 720.0, 646.0 / 1280.0);
               const vec2 K1 = vec2(390.1 / 720.0, 631.7 / 1280.0);
               const vec2 K2 = vec2(361.1 / 720.0, 632.7 / 1280.0);
               const vec2 K3 = vec2(360.0 / 720.0, 640.0 / 1280.0);

               const float T0 = 0.0;
               const float T1 = 3.0 / 90.0;
               const float T2 = 5.0 / 90.0;
               const float T3 = 10.0 / 90.0;
               const float T4 = 18.0 / 90.0;
               const float T5 = 1.0;

               const float S0 = 0.71;
               const float S1 = 0.951;
               const float S2 = 1.0;

               const float R0 = 17.0;
               const float R1 = 0.0;
               const float R2 = -8.0;

               vec2 mirrorUv(vec2 v) {
                 vec2 m = mod(v, 2.0);
                 return mix(m, 2.0 - m, step(1.0, m));
               }

               float easeInOutCubic(float t){
                 return t < 0.5
                 ? 4.0 * t * t * t
                 : 1.0 - pow(-2.0 * t + 2.0, 3.0) / 2.0;
               }


               vec2 pickKey(int i){
                 if ( i < 0) return K0;
                 else if (i == 1) return K1;
                 else if (i == 2) return K2;
                 else return K3;
               }

               vec2 catmullRom(vec2 p0, vec2 p1, vec2 p2, vec2 p3, float t){
                 float t2 = t * t, t3 = t2 * t;
                 return 0.5 * ((2.0 * p1)
                 + (-p0 + p2) * t
                 + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2
                 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
               }

               float catmullRom(float p0, float p1, float p2, float p3, float t){
                 float t2 = t * t, t3 = t2 * t;
                 return 0.5 * ((2.0 * p1)
                 + (-p0 + p2) * t
                 + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2
                 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
               }

               // effect uniforms
               void main() {

                 vec2 uv = sourceTextureCoordinate;
                 vec2 ratio = vec2(outputSize.xy / outputSize.y);
                 float p = progress;

                 float scaleVal;
                 float rotDeg;
                 vec2 targetUV;

                 if (p < T1){
                   float u = (p - T0) / (T1 - T0);
                   targetUV = catmullRom(K0, K0, K1, K2, u);
                 } else if (p < T2){
                   float u = (p - T1) / (T2 - T1);

                   targetUV = catmullRom(K0, K1, K2, K3, u);
                 } else if (p < T4){
                   float u = (p - T2) / (T4 - T2);
                   targetUV = catmullRom(K1, K2, K3, K3, u);
                 } else {
                   targetUV = K3;
                 }


                 if (p < T1){
                   float t = (p - T0) / (T1 - T0);
                   scaleVal = catmullRom(S0, S0, S1, S1, t);
                   rotDeg = catmullRom(R0, R0, R1, R2, t);
                 } else if (p < T3){
                   float t = (p - T1) / (T3 - T1);
                   scaleVal = catmullRom(S0, S1, S1, S2, t);
                   rotDeg = catmullRom(R0, R1, R2, R1, t);
                 } else if (p < T4){
                   float t = (p - T3) / (T4 - T3);
                   scaleVal = catmullRom(S1, S1, S2, S2, t);
                   rotDeg = catmullRom(R1, R2, R1, R1, t);
                 } else {
                   scaleVal = S2;
                   rotDeg = R1;
                 }

                 vec2 offset = targetUV - vec2(0.5);

                 float a = radians(rotDeg);
                 float c = cos(a);
                 float ss = sin(a);
                 mat2 rot2d = mat2(c, -ss, ss, c);


                 uv = uv - vec2(0.5);
                 uv *= ratio;

                 uv = rot2d * uv;
                 uv/= ratio;
                 uv -= offset;
                 uv /= scaleVal;
                 uv += vec2(0.5);

                 uv = mirrorUv(uv);

                 //motion blur
                 vec2 dir = uv - vec2(1.0,0.75);
                 float blurAmt = 0.025 * clamp(1.0 - progress/ 0.15, 0.0, 1.0);
                 vec4 c0 = sampleInput(uv);
                 vec4 c1 = sampleInput(uv - dir * (blurAmt * 0.33));
                 vec4 c2 = sampleInput(uv - dir * (blurAmt * 0.66));

                 vec4 color = (c0 + c1 + c2) / 3.0;
                 gl_FragColor = toOutputFormat(color);
               }
",
  "metal": "
using namespace metal;
struct fragmentIn { float2 sourceTextureCoordinate [[user(locn1)]]; };
struct fragmentOut { float4 _gl_FragColor [[color(0)]]; };
typedef struct {
  float4x4 content_transform;
  float4x4 texture_transform;
  float strength;
  float progress;
  float time_sec;
  float duration_sec;
  float clip_duration_sec;
  float2 input_size;
  float2 output_size;
 } Uniforms;

    float mod(float x, float y) { return x - y * floor(x / y); }
    float2 mod(float2 x, float2 y) { return x - y * floor(x / y); }
    float3 mod(float3 x, float3 y) { return x - y * floor(x / y); }
    float4 mod(float4 x, float4 y) { return x - y * floor(x / y); }
constant float2 K0 = float2(502.0 / 720.0, 646.0 / 1280.0);
constant float2 K1 = float2(390.1 / 720.0, 631.7 / 1280.0);
constant float2 K2 = float2(361.1 / 720.0, 632.7 / 1280.0);
constant float2 K3 = float2(360.0 / 720.0, 640.0 / 1280.0);

constant float T0 = 0.0;
constant float T1 = 3.0 / 90.0;
constant float T2 = 5.0 / 90.0;
constant float T3 = 10.0 / 90.0;
constant float T4 = 18.0 / 90.0;
constant float T5 = 1.0;

constant float S0 = 0.71;
constant float S1 = 0.951;
constant float S2 = 1.0;

constant float R0 = 17.0;
constant float R1 = 0.0;
constant float R2 = -8.0;

float2 mirrorUv(float2 v) {
    float2 m = mod(v, 2.0);
    return mix(m, 2.0 - m, step(1.0, m));
}

float easeInOutCubic(float t){
    return t < 0.5
    ? 4.0 * t * t * t
    : 1.0 - pow(-2.0 * t + 2.0, 3.0) / 2.0;
}


float2 pickKey(int i){
    if ( i < 0) return K0;
    else if (i == 1) return K1;
    else if (i == 2) return K2;
    else return K3;
}

float2 catmullRom(float2 p0, float2 p1, float2 p2, float2 p3, float t){
    float t2 = t * t, t3 = t2 * t;
    return 0.5 * ((2.0 * p1)
    + (-p0 + p2) * t
    + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2
    + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
}

float catmullRom(float p0, float p1, float p2, float p3, float t){
    float t2 = t * t, t3 = t2 * t;
    return 0.5 * ((2.0 * p1)
    + (-p0 + p2) * t
    + (2.0 * p0 - 5.0 * p1 + 4.0 * p2 - p3) * t2
    + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3);
}

// effect uniforms
fragment fragmentOut fragmentShader(fragmentIn in [[stage_in]],
 constant Uniforms & uniforms [[buffer(1)]],
 DefaultInputs defaultInputs) {

    float2 uv = in.sourceTextureCoordinate;
    float2 ratio = float2(uniforms.output_size.xy / uniforms.output_size.y);
    float p = uniforms.progress;

    float scaleVal;
    float rotDeg;
    float2 targetUV;

    if (p < T1){
    float u = (p - T0) / (T1 - T0);
    targetUV = catmullRom(K0, K0, K1, K2, u);
    } else if (p < T2){
    float u = (p - T1) / (T2 - T1);

    targetUV = catmullRom(K0, K1, K2, K3, u);
    } else if (p < T4){
    float u = (p - T2) / (T4 - T2);
    targetUV = catmullRom(K1, K2, K3, K3, u);
    } else {
    targetUV = K3;
    }


    if (p < T1){
    float t = (p - T0) / (T1 - T0);
    scaleVal = catmullRom(S0, S0, S1, S1, t);
    rotDeg = catmullRom(R0, R0, R1, R2, t);
    } else if (p < T3){
    float t = (p - T1) / (T3 - T1);
    scaleVal = catmullRom(S0, S1, S1, S2, t);
    rotDeg = catmullRom(R0, R1, R2, R1, t);
    } else if (p < T4){
    float t = (p - T3) / (T4 - T3);
    scaleVal = catmullRom(S1, S1, S2, S2, t);
    rotDeg = catmullRom(R1, R2, R1, R1, t);
    } else {
    scaleVal = S2;
    rotDeg = R1;
    }

    float2 offset = targetUV - float2(0.5);

    float a = (rotDeg * M_PI_F / 180.0);
    float c = cos(a);
    float ss = sin(a);
    float2x2 rot2d = float2x2(c, -ss, ss, c);


    uv = uv - float2(0.5);
    uv *= ratio;

    uv = rot2d * uv;
    uv/= ratio;
    uv -= offset;
    uv /= scaleVal;
    uv += float2(0.5);

    uv = mirrorUv(uv);

    //motion blur
    float2 dir = uv - float2(1.0,0.75);
    float blurAmt = 0.025 * clamp(1.0 - uniforms.progress/ 0.15, 0.0, 1.0);
    float4 c0 = sampleInput(defaultInputs, uv);
    float4 c1 = sampleInput(defaultInputs, uv - dir * (blurAmt * 0.33));
    float4 c2 = sampleInput(defaultInputs, uv - dir * (blurAmt * 0.66));

    float4 color = (c0 + c1 + c2) / 3.0;
    return {toOutputFormat(color)};
}
  ",
      "uniforms": {}
    }
  ]
}
