123

Pen Settings

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

You're using npm packages, so we've auto-selected Babel for you here, which we require to process imports and make it all work. If you need to use a different JavaScript preprocessor, remove the packages in the npm tab.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Use npm Packages

We can make npm packages available for you to use in your JavaScript. We use webpack to prepare them and make them available to import. We'll also process your JavaScript with Babel.

⚠️ This feature can only be used by logged in users.

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

            
              <canvas></canvas>
<!-- NOTE - does not work anymore - see note in JS window -->
            
          
!
            
              body{
  margin:0;
  padding: 0;
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: hidden;
}
/* NOTE - does not work anymore - see note in JS window -->
            
          
!
            
              // 6/4/2019 Oops! Didn't even realize this stopped working. Note - appears the main server has been taken offline so no more access to assets, etc :(, 
// keeping here in case anything might be helpful

//============= HELPERS =============
function normalize(value){
    var length = Math.sqrt(value[0] * value[0] + value[1] * value[1]);
    return [
        value[0] / length,
        value[1] / length
    ]
}

function randInt(min,max){
    return Math.floor(min + Math.random() * (max - min + 1));
}

/**
 * Pseudo scales the image, it's large so we need to scale it to be random, but
 * @param img
 * @returns {*}
 */
function scaleImage(img){
    var aspect = img.width / img.height;
    var randWidth = randInt(1,img.width * aspect);
    var randHeight = randInt(1,img.height* aspect);
    var width = img.width * 0.5;
    var height = img.height * 0.5;

    var ratio = 0;

    var dim = [0,0]


    if(width > randWidth){
        ratio = randWidth / width;
        dim[0] = randWidth;
        dim[1] = height * ratio;
        height = height * ratio;
        width = width * ratio;
    }

    if(height > randHeight){
        ratio = randHeight / height;
        dim[1] = randHeight;
        dim[0] = width * ratio;
    }

    return normalize(dim);

}
//============= PARTICLES  =============
var Particle = function(stage,img,scale,alpha){

    // reference to PIXI stage
    this.stage = stage;

    // reference to the particle image. Should pass in a PIXI.Sprite
    this.image = img;

    // randomly apply blend mode to particle
    var rand = Math.random();
    if(rand > 0.5){
        this.image.blendMode = PIXI.BLEND_MODES.ADD;
    }

    // scale for teh particle.
    this.scale = scale;

    // alpha for the particle.
    this.alpha = alpha;

    // is the particle visible
    this.visible = true;

    // has the particle been marked "dead" already
    this.markedDead = false;

    // initial velocity
    this.velocity = {
        x:Math.cos(Math.random() * Math.PI * 4.0) * 6.0,
        y:Math.sin(Math.random() * Math.PI * 4.0) * 6.0,
    };

    // rotation offset so particles rotate differently
    this.rotationOffset = Math.random();

    // add to stage
    this.stage.addChild(this.image);


};

Particle.prototype = {
    setFilter:function(filters){
        this.image.filters = filters;
    },
    getSprite:function(){
        return this.image;
    },

    // update function - run in render
    update:function(){

        // ensure particle is visible
        this._isVisible();

        // if particle is still on the stage
        if(this.visible){
            this.image.position.x += this.velocity.x;
            this.image.position.y += this.velocity.y;
            this.image.rotation += 0.01 * this.rotationOffset;
        }
    },


    // checks to see if the particle is still visible
    _isVisible:function(){
        var width = window.innerWidth;
        var height = window.innerHeight;
        var image = this.image;

        if(this.image.alpha > 0){
            this.image.alpha -= 0.01 * this.rotationOffset;
        }else if(this.image.alpha < 0){
            this.visible = false;
        }

        if(image.position.x > width + (image.width / 2) ||
            image.position.x < (image.width * -1)){
            this.visible = false;
        }


        if(image.position.y > height + (image.height / 2) ||
            image.position.y < (image.height * -1)){
            this.visible = false;
        }


    },

    // set starting position of particle and pivot point.
    setStartingPosition:function(origin){
        this.image.position.x = origin.x - this.image.width / 2;
        this.image.position.y = origin.y - this.image.height / 2;
        //this.image.pivot.set(-this.image.width / 2, this.image.height / 2);
    }
}

//============= SYSTEM =============
// Note - systems should get created in "mouseDownTouchStart"
var ParticleSystem = function(stage,images,isWebGL){

    // holds particles
    this.particles = [];

    // reference to PIXI stage
    this.stage = stage;

    // number of particles , hardcoded for now
    this.numParticles = 6;

    // reference to images for particles.
    this.images = images || [];

    // flag to mark whether or not the system is dead
    this.dead = false;

    // the number of "dead" particles
    this.particleDeadCount = 0;

    // setup filters if webgl
    // TODO : currently a bit resource intensive within the framework :(
    if(isWebGL){
        //this.filter = new PIXI.filters.BlurFilter();
    }

    this.isWebGL = isWebGL || false;

    // images should already have been loaded in load, just doing it here for testing
    //for(var i = 0; i < images.length;++i){
    //    this.images.push(PIXI.Texture.fromImage(images[i]));
    //}

    return this;
};

ParticleSystem.prototype = {
    // Create system. Init particles with random textures
    create:function(origin){
        var images = this.images;
        var stage = this.stage;

        // ensure that the origin is defined cause we have to push in a dummy system so
        // click events work
        if(origin !== undefined){

            for(var i = 0; i < this.numParticles; ++i){
                // pick a random image and generate a sprite
                var randIndex = Math.ceil(Math.random() * images.length - 1)
                var image = images[randIndex];
                var img =  new PIXI.Sprite(image);

                // random scale
                var scale = scaleImage(img);
                img.scale.set(scale[0],scale[1]);

                // random alpha
                img.alpha = Math.random();

                // tweak alpha so it doesn't go away too quickly
                if(img.alpha < 0.5){
                    img.alpha += 0.3;
                }

                // create particle
                var p = new Particle(stage,img);

                // set particle at the origin of click/tap
                p.setStartingPosition(origin);

                // add to particles array
                this.particles.push(p);

            }

        }

        return this;
    },
    size:function(){
        return this.particles.length;
    },
    update:function(){
        var len = this.numParticles;
        var stage = this.stage;
        for(var i = 0; i < len ; ++i) {
            this.particles[i].update();

            if(!this.particles[i].visible){
                stage.removeChild(this.particles[i].getSprite())
                if(!this.particles[i].markedDead){
                    this.particles[i].markedDead = true;
                    this.particleDeadCount += 1;
                }
            }
        }

        // mark system as dead so it can get popped from the main array of particle systems.
        if(this.particleDeadCount === this.particles.length){
            this.dead = true;
        }

    }
}


/*==== Ripple Filter ====*/
// based off of
// https://www.shadertoy.com/view/ldX3zr
// https://www.shadertoy.com/view/lds3RH

function RippleFilter(){
    var vertex = "attribute vec2 aVertexPosition;" +
        "attribute vec2 aTextureCoord;" +
        "uniform mat3 projectionMatrix;" +
        "varying vec2 vTextureCoord;" +
        "void main(void)\n{" +
        "vec2 pos = aVertexPosition;" +
        "gl_Position = vec4((projectionMatrix * vec3(pos, 1.0)).xy, 0.0, 1.0);\n    vTextureCoord = aTextureCoord;\n}";
    var fragment = [
        "precision highp float;",
        "uniform float beat;",
        "uniform float time;",
        "uniform vec2 resolution;",
        "uniform vec2 mousePos;",
        'uniform sampler2D uSampler;',

        'varying vec2 vTextureCoord;',

        "vec2 center = vec2(0.5,0.5);",
        "float speed = 0.05;",
        "float invAr = resolution.y / resolution.x;",
        "void main(){",
        "float vBeat = beat;",
        "float iGlobalTime = time;",
        "vec2 uv = gl_FragCoord.xy / resolution.xy;",
        //"vec2 uv = vTextureCoord;",

        "vec3 texcol;",
        "float x = (center.x - uv.x);",
        "float y = (center.y - uv.y) * invAr;",

        //"float r = -(x*x + y*y);",
        "float r = -((x * x + mousePos.x * mousePos.x) + (y * y + mousePos.y * mousePos.y));",
        "float z = 1.0 + beat * sin((r + iGlobalTime * speed) / 0.015);",

        "texcol.x = z;",
        "texcol.y = z;",
        "texcol.z = z * sin(r * time);",

        "float distanceFromCenter = sqrt(x * x + y * y);",
        "float sinArg = distanceFromCenter * 5.0 - time;",
        "float slope = sin(sinArg);",

        "texcol.xy *= mousePos;",
        "vec2 pos = vec2(x,y);",
        "vec4 tex = texture2D(uSampler, uv * normalize(pos + texcol.xy + vec2(beat)) * slope);",


        //  "vec4 tex = texture2D(uSampler, uv * normalize(vec2(x, y) + texcol.xy + mousePos) * slope);",
        "vec4 col = mix(tex,vec4(texcol * tex.xyz,1.),0.8);",
        "gl_FragColor = col;",
        "}"
    ].join("");

    PIXI.Filter.call(this,vertex,fragment,{
        time:{
            type:'f',
            value:0.0
        },
        beat:{
            type:'f',
            value:0.0
        },
        resolution:{
            type:'v2',
            value:[window.innerWidth,window.innerHeight]
        },
        mousePos:{
            type:'v2',
            value:[0.5,0.5]
        }
    });
}
RippleFilter.prototype = Object.create(PIXI.Filter.prototype);
RippleFilter.prototype.constructor = RippleFilter;


/*==== Chroma ===== */

// based off of this shader
// https://www.shadertoy.com/view/Mds3zn
function ChromaFilter() {
    var vertex = "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n    gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n    vTextureCoord = aTextureCoord;\n}";
    var fragment = [
        'varying vec2 vTextureCoord;',
        'uniform vec2 resolution;',
        'uniform float audioOffset;',
        'uniform sampler2D uSampler;',
        'void main(){',
        'float audio = audioOffset;',
        'vec2 uv = vTextureCoord;',
        'float amount = 0.0;',
        'amount = (1.0 + sin(audioOffset * 26.0)) * 0.5;',
        'amount *= 1.0 + sin(audioOffset) * 0.5;',
        'amount *= 0.5 + sin(audioOffset * 19.0) * 0.5;',
        'amount *= 1.0 + sin(27.0) * 0.5;',
        'amount = pow(amount, audioOffset);',


        'amount *= 0.05;',
        'vec3 col;',
        'col.r = texture2D( uSampler, vec2(uv.x+amount,uv.y) ).r;',
        'col.g = texture2D( uSampler, uv ).g;',
        'col.b = texture2D( uSampler, vec2(uv.x-amount,uv.y) ).b;',
        'col *= (1.0 - amount * 0.5);',

        'gl_FragColor = vec4(col,1.);',
        '}'
    ].join("");

    PIXI.Filter.call(this,vertex,fragment,{
        audioOffset:{
            type:'f',
            value:0.0
        }
    });
}

ChromaFilter.prototype = Object.create(PIXI.Filter.prototype);
ChromaFilter.prototype.constructor = ChromaFilter;
/**
 * An ASCII filter.
 *
 * @class
 * @extends PIXI.Filter
 * @memberof PIXI.filters
 */
function AsciiFilter()
{
    PIXI.Filter.call(this,
        // vertex shader
        "#define GLSLIFY 1\nattribute vec2 aVertexPosition;\nattribute vec2 aTextureCoord;\n\nuniform mat3 projectionMatrix;\n\nvarying vec2 vTextureCoord;\n\nvoid main(void)\n{\n    gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);\n    vTextureCoord = aTextureCoord;\n}",
        // fragment shader
        "#define GLSLIFY 1\nvarying vec2 vTextureCoord;\n\nuniform vec4 filterArea;\nuniform float pixelSize;\nuniform sampler2D uSampler;\n\nvec2 mapCoord( vec2 coord )\n{\n    coord *= filterArea.xy;\n    coord += filterArea.zw;\n\n    return coord;\n}\n\nvec2 unmapCoord( vec2 coord )\n{\n    coord -= filterArea.zw;\n    coord /= filterArea.xy;\n\n    return coord;\n}\n\nvec2 pixelate(vec2 coord, vec2 size)\n{\n    return floor( coord / size ) * size;\n}\n\nvec2 getMod(vec2 coord, vec2 size)\n{\n    return mod( coord , size) / size;\n}\n\nfloat character(float n, vec2 p)\n{\n    p = floor(p*vec2(4.0, -4.0) + 2.5);\n    if (clamp(p.x, 0.0, 4.0) == p.x && clamp(p.y, 0.0, 4.0) == p.y)\n    {\n        if (int(mod(n/exp2(p.x + 5.0*p.y), 2.0)) == 1) return 1.0;\n    }\n    return 0.0;\n}\n\nvoid main()\n{\n    vec2 coord = mapCoord(vTextureCoord);\n\n    // get the rounded color..\n    vec2 pixCoord = pixelate(coord, vec2(pixelSize));\n    pixCoord = unmapCoord(pixCoord);\n\n    vec4 color = texture2D(uSampler, pixCoord);\n\n    // determine the character to use\n    float gray = (color.r + color.g + color.b) / 3.0;\n\n    float n =  65536.0;             // .\n    if (gray > 0.2) n = 65600.0;    // :\n    if (gray > 0.3) n = 332772.0;   // *\n    if (gray > 0.4) n = 15255086.0; // o\n    if (gray > 0.5) n = 23385164.0; // &\n    if (gray > 0.6) n = 15252014.0; // 8\n    if (gray > 0.7) n = 13199452.0; // @\n    if (gray > 0.8) n = 11512810.0; // #\n\n    // get the mod..\n    vec2 modd = getMod(coord, vec2(pixelSize));\n\n    gl_FragColor = color * character( n, vec2(-1.0) + modd * 2.0);\n\n}"
    );

    this.size = 8;
}

AsciiFilter.prototype = Object.create(PIXI.Filter.prototype);
AsciiFilter.prototype.constructor = AsciiFilter;

Object.defineProperties(AsciiFilter.prototype, {
    /**
     * The pixel size used by the filter.
     *
     * @member {number}
     * @memberof PIXI.filters.AsciiFilter#
     */
    size: {
        get: function ()
        {
            return this.uniforms.pixelSize;
        },
        set: function (value)
        {
            this.uniforms.pixelSize = value;
        }
    }
});


/**
 * The BloomFilter applies a Gaussian blur to an object.
 * The strength of the blur can be set for x- and y-axis separately.
 *
 * @class
 * @extends PIXI.Filter
 * @memberof PIXI.filters
 */
function BloomFilter()
{
    PIXI.Filter.call(this);

    this.blurXFilter = new PIXI.filters.BlurXFilter();
    this.blurYFilter = new PIXI.filters.BlurYFilter();

    this.blurYFilter.blendMode = PIXI.BLEND_MODES.SCREEN;

    this.defaultFilter = new PIXI.filters.VoidFilter();
}

BloomFilter.prototype = Object.create(PIXI.Filter.prototype);
BloomFilter.prototype.constructor = BloomFilter;

BloomFilter.prototype.apply = function (filterManager, input, output)
{
    var renderTarget = filterManager.getRenderTarget(true);

    //TODO - copyTexSubImage2D could be used here?
    this.defaultFilter.apply(filterManager, input, output);

    this.blurXFilter.apply(filterManager, input, renderTarget);
    this.blurYFilter.apply(filterManager, renderTarget, output);

    filterManager.returnRenderTarget(renderTarget);
};

Object.defineProperties(BloomFilter.prototype, {
    /**
     * Sets the strength of both the blurX and blurY properties simultaneously
     *
     * @member {number}
     * @memberOf PIXI.filters.BloomFilter#
     * @default 2
     */
    blur: {
        get: function ()
        {
            return this.blurXFilter.blur;
        },
        set: function (value)
        {
            this.blurXFilter.blur = this.blurYFilter.blur = value;
        }
    },

    /**
     * Sets the strength of the blurX property
     *
     * @member {number}
     * @memberOf PIXI.filters.BloomFilter#
     * @default 2
     */
    blurX: {
        get: function ()
        {
            return this.blurXFilter.blur;
        },
        set: function (value)
        {
            this.blurXFilter.blur = value;
        }
    },

    /**
     * Sets the strength of the blurY property
     *
     * @member {number}
     * @memberOf PIXI.filters.BloomFilter#
     * @default 2
     */
    blurY: {
        get: function ()
        {
            return this.blurYFilter.blur;
        },
        set: function (value)
        {
            this.blurYFilter.blur = value;
        }
    }
});

/**
 * Creates a duel container setup with two containers taking up half the screen
 * @param input the input object from the SPF framework
 * @param tex1 the texture for the left half
 * @param tex2 the texture for the right half
 * @returns {{left: PIXI.Container, right: PIXI.Container, stage: (*|null), getHalfWidth: getHalfWidth, addSpriteToLeft: addSpriteToLeft, addSpriteToRight: addSpriteToRight}}
 * @constructor
 */

function MultiStage(input,tex1,tex2){
    var stageLeft = new PIXI.Container();
    var stageRight = new PIXI.Container();
    var width = input.width;
    var height = input.height;
    var stage = input.container;
    var chroma = new ChromaFilter();
    var count = 0;
    // masks used to give a defined edge to each container
    var leftMask = new PIXI.Graphics();
    var rightMask = new PIXI.Graphics();

    stageLeft.x = 0;
    stageRight.x = width / 2;
    stageRight.x += 120;

    var bg = null;
    var bg2 = null

    if(tex1 instanceof PIXI.Texture){
        bg = tex1;
    }else{
        bg = PIXI.Texture.fromImage(tex1);
    }

    if(tex2 instanceof PIXI.Texture){
        bg2 = tex2;
    }else{
        bg2 = PIXI.Texture.fromImage(tex2);
    }

    bg = new PIXI.extras.TilingSprite(bg);
    bg2 = new PIXI.extras.TilingSprite(bg2);

    if(window.CAN_USE_WEBGL){
        bg.filters = [chroma];
        bg2.filters = [chroma];
    }

    bg.width = width / 2;
    bg2.width = width / 2;

    bg.height = height;
    bg2.height = height;

    stageLeft.addChild(bg);
    stageRight.addChild(bg2);

    stage.addChild(stageLeft);
    stage.addChild(stageRight);

    // add masks so we can hide edges
    leftMask.clear();
    leftMask.beginFill(input.colors[10], 0.8);
    leftMask.drawRect(0,0,input.width / 2,input.height);
    leftMask.endFill();

    rightMask.clear();
    rightMask.beginFill(input.colors[10], 0.8);
    rightMask.drawRect(0,0,input.width / 2,input.height);
    rightMask.endFill();

    rightMask.position.x = input.width / 2;

    stage.addChild(leftMask);
    stage.addChild(rightMask);

    stageLeft.mask = leftMask;
    stageRight.mask = rightMask;

    return {
        bg:bg,
        bg2:bg2,
        left:stageLeft,
        right:stageRight,
        main:stage,
        leftMask:leftMask,
        rightMask:rightMask,
        filter:chroma,
        updateFilters:function(){
            this.filter.uniforms.audioOffset = Math.random();
        },

        renderMask:function(input){
            count += 0.01;
            var audio = input.audio.frequencies();
            this.leftMask.clear();
            this.leftMask.beginFill(input.colors[10], 0.4);
            this.leftMask.drawRect(0,0,input.width / 2,input.height);
            this.leftMask.endFill();

            this.rightMask.clear();
            this.rightMask.beginFill(input.colors[9], 0.4);
            this.rightMask.drawRect(0,0,input.width / 2,input.height);
            this.rightMask.endFill();

        },

        // re-sizes all the containers and backgrounds
        resizeContainers:function(input){
            bg.width = input.width / 2;
            bg2.width = input.width / 2;
            bg.height = input.height;
            bg2.height = input.height;


            stageLeft.x = 0;
            stageRight.x = input.width / 2;

            this.leftMask.clear();
            this.leftMask.beginFill(input.colors[10], 1);
            this.leftMask.drawRect(0,0,input.width / 2,input.height);
            this.leftMask.endFill();

            this.rightMask.clear();
            this.rightMask.beginFill(input.colors[10], 1);
            this.rightMask.drawRect(0,0,input.width / 2,input.height);
            this.rightMask.endFill();

            rightMask.position.x = input.width / 2;


        },

        /**
         * Add sprite to the left PIXI.Container. Needs to be a path so a new
         * sprite can be created. Returns newly created sprite
         * @param itm path to sprite.
         * @returns {PIXI.extras.TilingSprite|PIXI.Texture|PIXI.Sprite|PIXI.BaseTexture}
         */
        addSpriteToLeft:function(itm){
            var sprite = new PIXI.Sprite(itm);
            this.left.addChild(sprite);
            return sprite;
        },

        /**
         * Add sprite to the right PIXI.Container. Needs to be a path so a new
         * sprite can be created. Returns newly created sprite
         * @param itm path to sprite.
         * @returns {PIXI.extras.TilingSprite|PIXI.Texture|PIXI.Sprite|PIXI.BaseTexture}
         */
        addSpriteToRight:function(itm){
            var sprite = new PIXI.Sprite(itm)

            // the right side should mirror left, flip scaling
            //sprite.scale.x = -1;

            this.right.addChild(sprite);
            return sprite;
        }
    }
}/**
 * Created by sortofsleepy on 1/16/17.
 */
      // check for webgl because webgl is the only mask that can use filters
    function webglCheck(){
        var tmp = document.getElementsByTagName("canvas")[0];
        if(tmp.getContext('webgl') !== null){
            window.CAN_USE_WEBGL = true;
            return true;
        }else{
            return false;
        }
    }
    var count = 0;
    var isWebGL = webglCheck();
    var bgs = [];
    var colorMatrixOne = null;
    var colorMatrixTwo = null;
    var ascii = null;
    var bloom = null;

    if(isWebGL){
        colorMatrixOne = new PIXI.filters.ColorMatrixFilter();
        colorMatrixTwo = new PIXI.filters.ColorMatrixFilter();
        ascii = new AsciiFilter();


    }


    // ========= BACK LAYER VARS ========== //
    var stages = null;
    var sprites = [];

    //======= LEFT STAGE OBJECTS ==========
    var bird;
    var birdOverlay;
    var birdOverlay2;
    var birdOverlay3;
    //======= RIGHT STAGE OBJECTS ==========
    var birdReflect;
    var birdReflectOverlay;
    var birdReflectOverlay2;
    var birdReflectOverlay3;
    SPF.set({
        at:"back",
        load:function(PIXI,input){
            bgs = [
                input.patterns.botanicorganic4,
                input.patterns.handdrawnanimal2
            ]

            sprites = [
                input.graphics.bbbbird1
            ]
            return bgs;
        },
        init: function(PIXI, input) {
            stages = MultiStage(input,bgs[0],bgs[1]);

            //======= LEFT STAGE OBJECTS ==========
            bird = stages.addSpriteToLeft(sprites[0]);
            birdOverlay = stages.addSpriteToLeft(sprites[0]);
            birdOverlay2 = stages.addSpriteToLeft(sprites[0])
            birdOverlay3 = stages.addSpriteToLeft(sprites[0])

            bird.anchor.x = 0.5;
            bird.anchor.y = 0.5;
            bird.position.x = input.width / 2;
            bird.position.y = input.height / 2;

            birdOverlay.anchor.x = 0.5;
            birdOverlay.anchor.y = 0.5;
            birdOverlay.position.x = input.width / 2;
            birdOverlay.position.y = input.height / 2;

            birdOverlay2.anchor.x = 0.5;
            birdOverlay2.anchor.y = 0.5;
            birdOverlay2.position.x = input.width / 2;
            birdOverlay2.position.y = input.height / 2;

            birdOverlay3.anchor.x = 0.5;
            birdOverlay3.anchor.y = 0.5;
            birdOverlay3.position.x = input.width / 2;
            birdOverlay3.position.y = input.height / 2;


            //======= RIGHT STAGE OBJECTS ==========
            birdReflect = stages.addSpriteToRight(sprites[0])
            birdReflectOverlay = stages.addSpriteToRight(sprites[0])
            birdReflectOverlay2 = stages.addSpriteToRight(sprites[0])
            birdReflectOverlay3 = stages.addSpriteToRight(sprites[0])

            birdReflect.scale.x = -1;
            birdReflect.anchor.x = 0.5;
            birdReflect.anchor.y = 0.5;
            birdReflect.position.y = input.height / 2;

            birdReflectOverlay.scale.x = -1;
            birdReflectOverlay.anchor.x = 0.5;
            birdReflectOverlay.anchor.y = 0.5;
            birdReflectOverlay.position.y = input.height / 2;


            birdReflectOverlay2.scale.x = -1;
            birdReflectOverlay2.anchor.x = 0.5;
            birdReflectOverlay2.anchor.y = 0.5;
            birdReflectOverlay2.position.y = input.height / 2;

            birdReflectOverlay3.scale.x = -1;
            birdReflectOverlay3.anchor.x = 0.5;
            birdReflectOverlay3.anchor.y = 0.5;
            birdReflectOverlay3.position.y = input.height / 2;



            //====== ADD FILTERS IF POSSIBLE =========
            if(isWebGL){
                bird.filters = [colorMatrixOne,ascii]
                birdOverlay.filters = [colorMatrixOne]
                birdOverlay2.filters = [colorMatrixOne];
                birdOverlay3.filters = [colorMatrixOne,ascii]

                birdReflect.filters = [colorMatrixTwo,ascii]
                birdReflectOverlay.filters = [colorMatrixTwo];
                birdReflectOverlay2.filters = [colorMatrixTwo]
                birdReflectOverlay3.filters = [colorMatrixOne,ascii]

            }
        },
        render:function(PIXI,input){
            var audio = input.audio.frequencies();
            count += 0.1;
            //======= LEFT STAGE OBJECTS =======
            bird.rotation += 0.01;
            birdOverlay.rotation -= 0.01 * Math.random() + (audio[Math.round(audio.length/4)]/200);
            birdOverlay2.rotation += 0.01 * 0.2 + (audio[Math.round(audio.length/4)]/200);
            birdOverlay3.rotation -=  0.05 + (audio[Math.round(audio.length/4)]/1000);
            //======== RIGHT STAGE OBJECTS ========
            birdReflect.rotation -= 0.01;
            birdReflectOverlay.rotation += 0.01 * Math.random() + (audio[Math.round(audio.length/4)]/200);
            birdReflectOverlay2.rotation -= 0.01 * 0.2 + (audio[Math.round(audio.length/4)]/200);
            birdReflectOverlay3.rotation +=  0.05 + (audio[Math.round(audio.length/4)]/1000);
            // render the mask so we can properly divide the stage borders
            stages.renderMask(input);

            // update filters if necessary
            if(isWebGL){
                if(input.beat !== null){
                    stages.updateFilters();
                }

            }


            var matrix = colorMatrixOne.matrix;
            var matrix2 = colorMatrixTwo.matrix;

            matrix[1] = Math.sin(audio[Math.round(audio.length/2)]/1000) * 3.0;
            matrix[2] = Math.cos(audio[2] / 1000.0) * 4.0;
            matrix[3] = Math.cos(audio[3] / 1000.0) * 1.5;
            matrix[4] = Math.sin(audio[4] / 300) * 2;
            matrix[5] = Math.sin(audio[5] / 200);
            matrix[6] = Math.sin(audio[6] / 400);

            matrix2[1] = matrix[1] * -1;
            matrix2[2] = matrix[1] * -1;
            matrix2[3] = matrix[1] * -1;
            matrix2[4] = matrix[1] * -1;
            matrix2[5] = matrix[1] * -1;
            matrix2[6] = matrix[1] * -1;

        },
        mouseDownTouchStart:function(PIXI,input){

        },
        resize :function(PIXI, input) {

            var w =  input.width;
            var h =  input.height;

            stages.resizeContainers(input);

            // ====== LEFT SIDE RESIZING ======
            bird.anchor.x = 0.5;
            bird.anchor.y = 0.5;
            bird.position.x = input.width / 2;
            bird.position.y = input.height / 2;

            birdOverlay.anchor.x = 0.5;
            birdOverlay.anchor.y = 0.5;
            birdOverlay.position.x = input.width / 2;
            birdOverlay.position.y = input.height / 2;

            birdOverlay2.anchor.x = 0.5;
            birdOverlay2.anchor.y = 0.5;
            birdOverlay2.position.x = input.width / 2;
            birdOverlay2.position.y = input.height / 2;

            birdOverlay3.anchor.x = 0.5;
            birdOverlay3.anchor.y = 0.5;
            birdOverlay3.position.x = input.width / 2;
            birdOverlay3.position.y = input.height / 2;


            // ====== RIGHT SIDE RESIZING ======
            birdReflect.scale.x = -1;
            birdReflect.anchor.x = 0.5;
            birdReflect.anchor.y = 0.5;
            birdReflect.position.y = input.height / 2;

            birdReflectOverlay.scale.x = -1;
            birdReflectOverlay.anchor.x = 0.5;
            birdReflectOverlay.anchor.y = 0.5;
            birdReflectOverlay.position.y = input.height / 2;


            birdReflectOverlay2.scale.x = -1;
            birdReflectOverlay2.anchor.x = 0.5;
            birdReflectOverlay2.anchor.y = 0.5;
            birdReflectOverlay2.position.y = input.height / 2;

            birdReflectOverlay3.scale.x = -1;
            birdReflectOverlay3.anchor.x = 0.5;
            birdReflectOverlay3.anchor.y = 0.5;
            birdReflectOverlay3.position.y = input.height / 2;



        }

    })
    // ========= FORE LAYER ==============
    // particle layer - particles should originate close to the center
    // every time on beat.
    // System management is built in.
    var particleBeat = false;
    var systems = [];
    var maxSystems = 8;
    // PARTICLES
    SPF.set({
        at: "fore",
        load:function(PIXI,input){
            particleAssets = [
                input.graphics.animaltech,
                input.graphics.leaf2,
                input.graphics.handdrawnanimal1,
                input.graphics.bbbbird3,
                input.graphics.leaf1,
                input.graphics.crazyflower3,
                input.graphics.crazyflower2,
                input.graphics.wingwave

            ]

            // need to push a dummy container to get events to work properly for some reason
            systems.push(new ParticleSystem(input.container,particleAssets).create());
            return particleAssets;
        },

        init:function(PIXI,input){
            // if we're on a desktop, increase max limit of systems a bit more
            if(!input.isTouchDevice){
                maxSystems = 20;
            }
        },

        render:function(PIXI,input){
            for(var i = 1; i < systems.length;++i){
                systems[i].update();

                // remove "dead" systems from memory to help keep perf up.
                if(systems[i].dead === true){
                    systems.splice(i,1);
                }
            }

            /**
             * On desktop class devices, lets automatically add particles as well
             */
            if(!input.isTouchDevice){
                if(input.frameRate > 30){
                    // ensure beat only happens once so we can cycle through properly
                    if(input.beat !== null){
                        particleBeat = true;
                    }else{
                        if(particleBeat){
                            var width = input.width;
                            var height = input.height;
                            var stageSide = Math.floor(Math.random() * 10);
                            var addSide = null;
                            var x = width / 2;
                            var y = height / 2;
                            var system = null;
                            if(stageSide > 5){
                                addSide = stages.left
                                system = new ParticleSystem(addSide,particleAssets,isWebGL).create({
                                    x:x,
                                    y:y
                                });
                            }else {
                                addSide = stages.right;
                                x = 0;
                                system = new ParticleSystem(addSide,particleAssets,isWebGL).create({
                                    x:x,
                                    y:y
                                });


                                // ensure particles on the right side don't just immediately
                                // fall off.
                                var particles = system.particles;
                                var len = particles.length;
                                for(var i = 0; i < len; ++i){
                                    var vel = particles[i].velocity.x;
                                    if(vel < 0){
                                        particles[i].velocity.x *= -1;
                                    }
                                }
                            }

                            systems.push(system);
                            particleBeat = false;
                        }
                    }
                }
            }
        }
    });
    SPF.info({
        debug: false,
        title: "Crazybird",
        tip: "Non-interactive - enjoy the show",
        firstName: "Joe",
        lastName: "Chow",
        email: "joe@xoio.co"
    });
    SPF.start()

            
          
!
999px
🕑 One or more of the npm packages you are using needs to be built. You're the first person to ever need it! We're building it right now and your preview will start updating again when it's ready.

Console