Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URLs added here will be added as <link>s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.

+ add another resource

JavaScript

Babel includes JSX processing.

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

Packages

Add Packages

Search for and use JavaScript packages from npm here. By selecting a package, an import statement will be added to the top of the JavaScript editor for this package.

Behavior

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.

Format on Save

If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML

              
                <div id="canvas-holder"></div>

              
            
!

CSS

              
                
              
            
!

JS

              
                
var NUM_CIRCLES = 22;
var MAX_RADIUS = 150;
var FRICTION = 1;
var SPEED_DIVISOR = 500;
var WEIGHT_1 = 5;
var WEIGHT_2 = 3.5;
var SPREAD = 5;

// Vars -
var _loader;
var _imgTexture;
var _stage;
var _target;
var _renderer;
var _mouseDown = false;
var _circles = [];
// Stage width & height - 
var _sw;
var _sh;

// Start Mouse X & Y at not 0 for some initial movement - 
var _mouseX = 25;
var _mouseY = 25;

const context = new (window.AudioContext || window.webkitAudioContext)();
//var context = new AudioContext();
var osc = context.createOscillator();
var vol = context.createGain();
var osc2 = context.createOscillator();
var vol2 = context.createGain();
var real = new Float32Array(2);
var imag = new Float32Array(2);
real[0] = 0.2;
imag[0] = 0.4;
real[1] = 0.8;
imag[1] = -1;
var push = false;
var wave = context.createPeriodicWave(real, imag, {disableNormalization: true});
const lfo = context.createOscillator();  
const modulationGain = context.createGain();  
function soundSetup(){
vol.gain.value = 0.01; // from 0 to 1, 1 full volume, 0 is muted
osc.connect(vol); // connect osc to vol
vol.connect(context.destination); // connect vol to context destination
//osc.start(context.currentTime); // start it three seconds from now
vol2.gain.value = 2.0; // from 0 to 1, 1 full volume, 0 is muted
osc2.connect(vol2); // connect osc to vol
vol2.connect(context.destination); // connect vol to context destination
//osc2.start(context.currentTime); // start it three seconds from now
osc.setPeriodicWave(wave);

  lfo.frequency.value = 5.0;
  
  modulationGain.gain.value = 50;  // Configure the graph and start the oscillators  
  lfo.connect(modulationGain);  
  modulationGain.connect(osc2.frequency);
  modulationGain.connect(osc.detune);
}
function init() {


    soundSetup();
    // Call the resize function to set up defaults -
    resizeIt();
    // On resize, recall the resize function -
    window.onresize = resizeIt;

    // Set up out Pixi instance -
    _stage = new PIXI.Stage();
    _renderer = PIXI.autoDetectRenderer(_sw, _sh);
    _renderer.backgroundColor = 0xffffff; 
    _renderer.view.style.display = "block";

    // Add some Mouse & Touch events -
    _stage.on('mousedown', onMouseDown);
    _stage.on('touchstart', onMouseDown);
    _stage.on('mousemove', onMouseMove);
    _stage.on('touchmove', onMouseMove);
    _stage.on('mouseup', onMouseUp);
    _stage.on('touchend', onMouseUp);

    // Tell the stage that it should be interactive -
    _stage.interactive = true;
    _stage.hitArea = new PIXI.Rectangle(0, 0, _sw, _sh);

    // Add render view to DOM
    document.getElementById("canvas-holder").appendChild(_renderer.view);

    // Make our main container, and add it to the stage -
    _target = new PIXI.Container();
    _target.position.x = _sw / 2 -15 ;
    _target.position.y = 0 + MAX_RADIUS + 90;
    _stage.addChild(_target);

    // Make a loader to "load" the image -
    _loader = new PIXI.loaders.Loader();
    _loader.add("img", _myImage);
    _loader.once('complete', addCircles);

    // Begin loading -
    _loader.load();
}

function addCircles() {

    // Create a texture from the image -
    _imgTexture = PIXI.utils.TextureCache[_myImage];

    // Make the circles -
    for (var i = 0; i < NUM_CIRCLES; i++) {

        // Set the radius to be between the max and 0 - based on the current index of the loop.
        var radius = map(i, 0, NUM_CIRCLES - 1, MAX_RADIUS, 0);

        // Create a container -
        var circleHolder = new PIXI.Container();

        // Create a sprite from the texture -
        var circleSprite = new PIXI.Sprite(_imgTexture);

        // Center the sprite -
        circleSprite.anchor.x = 0.5
        circleSprite.anchor.y = 0.5;

        // Add it to the holder -
        circleHolder.addChild(circleSprite);

        // Create a circular graphic to use as a mask -
        var circleMask = new PIXI.Graphics();
        circleMask.beginFill(0xFFFFFF);
        circleMask.drawCircle(0, 0, radius);
        circleMask.endFill();

        // Add it to the container -
        circleHolder.addChild(circleMask);

        // Set it as the mask of the sprite -
        circleSprite.mask = circleMask;

        // Set some properties, to be used later for the animation -
      
      circleHolder.speedX = 0;
        circleHolder.speedY = 0;
        circleHolder.distX = 0;
        circleHolder.distY = 0;

        // Add a weight, mapped between the 2 variables, again, based on the loop index
        circleHolder.weight = map(i, 0, NUM_CIRCLES - 1, WEIGHT_1, WEIGHT_2);

        // Cache the whole clip as a bitmap
        circleHolder.cacheAsBitmap = true;

        // Add it to an array of the circles -
        _circles.push(circleHolder);

        // Add the clip to the target container -
        _target.addChild(circleHolder);
    }

    // Initial call of the animate funciton -
    setrand() ;
    animate();
}

function resizeIt() {

    // Calculate our size vars -
    _sw = window.innerWidth;
    _sh = window.innerHeight;

    // Resize the renderer -
    if (_renderer) {
        _renderer.resize(_sw, _sh);
        _stage.hitArea = new PIXI.Rectangle(0, 0, _sw, _sh);
    }
    // Recenter our container -
    if (_target) {
        _target.position.x = _sw / 2;
        _target.position.y = - MAX_RADIUS/2 + 90;
    }

}
var fr = 0.00; 
function animate() {

    var circ;

    // For each circle -
    for (var i = _circles.length - 1; i >= 0; i--) {

        circ = _circles[i];
        
      
        
        // Calculate the distance to the mouse -
        circ.distX = Math.floor(circ.position.x - _mouseX);
        circ.distY = Math.floor(circ.position.y - _mouseY);
        
        // Divide the distance to make the transition not instant, and add that to its speed
        circ.speedX += circ.distX / SPEED_DIVISOR;
        circ.speedY += circ.distY / SPEED_DIVISOR;

        // Reposition the circle based on its speed & weight variables -
        circ.position.x -= circ.speedX * circ.weight;
        circ.position.y -= circ.speedY * circ.weight;
        //if (circ.position.x > _sw || circ.position.x < 0) circ.speedX = -circ.speedX;
        //if (circ.position.y > _sh || circ.position.y < 0) circ.speedY = -circ.speedY;
        // Apply friction to the circle's speed -
        if(push){
        circ.speedX+=random(SPREAD);
        circ.speedY+=random(SPREAD);
          
    }
        circ.speedX *= FRICTION;
        circ.speedY *= FRICTION;
    }
    push = false;
    fr = map(_circles[_circles.length - 1].distX,0,1000,50,500);
    osc.frequency.setValueAtTime(fr, context.currentTime);
    fr = map(_circles[0].distX,0,1000,50,200);
    osc2.frequency.setValueAtTime(fr, context.currentTime);
    // Render the stage -
    _renderer.render(_stage);
 
    // Call animate again -
    requestAnimationFrame(animate);
}
var timer;
function onMouseDown(mouseData) {
    
    // Set the mouse down flag -
    _mouseDown = true;
    timer = context.currentTime;
    console.log(timer);
    // Set the mouse position vars -
    var mouse = mouseData.data.getLocalPosition(_stage);
    _mouseX = mouse.x/2 - _sw / 4;
    _mouseY = mouse.y/2 - MAX_RADIUS/2 + 90 ;
}
var click  = false;
function onMouseMove(mouseData) {
    if (_mouseDown) {
        // Set the mouse position vars -
        var mouse = mouseData.data.getLocalPosition(_stage);
        _mouseX = mouse.x/2 - _sw / 4;
        _mouseY = mouse.y/2 - MAX_RADIUS/2 + 90;
    }
}
var firstTime = true;
function onMouseUp() {
  
	if(firstTime){
	osc.start(context.currentTime);
	osc2.start(context.currentTime);
	firstTime = false;
	}
    if(context.currentTime - timer < 0.1 && !click) click = true;
    else if(context.currentTime - timer < 0.15 && click) {
      reset();
      click = false;
    }
    else {
      click = false;
          push = true;
         }
    _mouseDown = false;

}
function reset() {
      _mouseX = 0;
      _mouseY = 0;
      for (var i = _circles.length - 1; i >= 0; i--) {

        circ = _circles[i];
               
        // Calculate the distance to the mouse -
        circ.distX = random(0);
        circ.distY = random(0);

        // Divide the distance to make the transition not instant, and add that to its speed
        circ.speedX = 0.5;
        circ.speedY = 0.2;

        // Reposition the circle based on its speed & weight variables -
        circ.position.x = random(0);
        circ.position.y = random(0);
    }
}

function setrand() {
     
}

function random(max) {
  return Math.floor(Math.random() * max);
}
// Maths utility to map numbers from one range to another -
function map(v, a, b, x, y) {
    return (v == a) ? x : (v - a) * (y - x) / (b - a) + x;
}

const imgs = [ 
"https://static.tildacdn.com/tild3239-6265-4438-a537-373931346565/3.png",
"https://static.tildacdn.com/tild6264-6361-4633-b937-303762626336/9.png",
"https://static.tildacdn.com/tild6130-3666-4530-b565-396239383464/4.png",
"https://static.tildacdn.com/tild3461-3537-4432-a563-366531646136/6.png",
"https://static.tildacdn.com/tild3665-3433-4731-a337-373534643366/5.png",
"https://static.tildacdn.com/tild3739-3133-4763-b836-643235643634/121043020027.png",
"https://static.tildacdn.com/tild3861-3136-4631-b361-343735376139/7.png",
];

const rand = Math.floor(Math.random() * imgs.length);
var _myImage = imgs[rand];
// Start -
init();

              
            
!
999px

Console