cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - ActiveLovehtmlicon-new-collectionicon-personicon-teamlog-outoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External CSS

These stylesheets will be added in this order and before the code you write in the CSS editor. You can also add another Pen here, and it will pull the CSS from it. Try typing "font" or "ribbon" below.

Quick-add: + add another resource

Add External JavaScript

These scripts will run in this order and before the code in the JavaScript editor. You can also link to another Pen here, and it will run the JavaScript from it. Also try typing the name of any popular library.

Quick-add: + add another resource

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.

            
                  <section id="wrapper">
  <div id="title">
    <h1>Catch Omanyte!</h1>
    <p>Works best on a mobile device in <a href="https://codepen.io/zingchart/full/BzmdwQ">fullscreen</a> </p>
  </div>
  <div id="info-button" onclick="toggleInfoScreen()">?</div>
  <div id="info-screen" class="hidden">
    <div id="info-shade"></div>
    <div id="info-text">
      <h3>Catch Omanyte:</h3>
      <ul>
        <li>Swipe the pokeball straight up, with just enough velocity </li>
        <li>The smaller the green circle, the greater chance in catching omanyte!</li>
      </ul>
      <h3>Built with:</h3>
      <ul>
        <li><a href="https://zingchart.github.io/zingtouch">ZingTouch</a> - A JavaScript gesture detection library</li>
        <li><a href="http://anime-js.com/">Anime.js</a> - a flexible yet lightweight JavaScript animation library.</li>
      </ul>

      <h3>Brought to you by <a href="https://zingchart.com/">ZingChart</a></h3>
      <span style="font-size: 0.8em;">Disclaimer: ZingChart does not own or is affiliated to the character Omanyte or the pokeball item. This is simply a demonstration of web technologies by people who love playing Pokemon Go!</span>
    </div>

  </div>
  <div id="touch-layer"></div>
  <div id="particles"></div>
  <div id="ring-screen">
    <div id="ring">
      <div id="ring-active">
        <div id="ring-fill"></div>
      </div>
    </div>
  </div>
  <div id="screen" class="gradient-background">
    <div id="target-container">
      <div id="target"></div>
    </div>
    <div id="ball"></div>
    <div id="output"></div>
  </div>


  <div id="capture-screen" class="gradient-background hidden">
    <div id="capture-status" class="hidden">
      You caught Omanyte!
    </div>
    <div id="poof-container" class="hidden">
      <div id="poof"></div>
    </div>
    <div id="capture-confetti"></div>
    <div id="capture-ball"></div>
    <div id="capture-ball-button-container" class="hidden">
      <div id="capture-ball-button"></div>
    </div>
  </div>


</section>
            
          
!
            
              @import 'https://fonts.googleapis.com/css?family=Open+Sans:400,600';
* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  padding: 0;
  font-family: "Open Sans";
  width: 100%;
  height: 100%;
}

h1,
p {
  margin: 0;
}

ul {
  margin: 0;
}

a {
  color: rgb(71, 211, 255);
}



.gradient-background {
  background: #00c6ff;
  background: -webkit-linear-gradient(top, #1e5799 0%, #00c6ff 25%, #26c6da 55%, #7AE3EF 100%);
  background: linear-gradient(to bottom, #1e5799 0%, #00c6ff 25%, #26c6da 55%, #7AE3EF 100%)
}

#screen,
#wrapper,
#touch-layer,
#waves,
#info-screen {
  position: relative;
  height: 100%;
  width: 100%;
}

#title {
  position: fixed;
  text-align: center;
  width: 100%;
  color: white;
  margin-top: 0.5em;
  z-index: 11;
}

#screen,
#capture-screen,
#ring-screen {
  @extend .flex-center;
  position: relative;
}


/* Accuracy ring */

#ring-screen {
  @extend .flex-center;
  height: 100%;
  width: 100%;
  position: absolute;
  z-index: 3;
}

#ring {
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  width: 150px;
  height: 150px;
  border: 2px solid white;
  border-radius: 100px;
}

#ring-active {
  border: 2px solid #64DD17;
  border-radius: 100px;
}

#ring-fill {
  width: 150px;
  height: 150px;
}


/* Capture Screen */

#capture-screen {
  display: flex;
    @extend .fixed-full-width;

  flex-direction: column;
  background-color: #222;

  z-index: 12;
}

#poof-container {
  @extend .flex-center;
  position: fixed;
  z-index: 10;
  height: 100%;
  width: 100%;
  top: 0;
  left: 0;
}

#poof {
  width: 100%;
  height: 20px;
  opacity: 0.8;
  background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/pkmngo-poof.svg');
  background-repeat: no-repeat;
  background-position: center center;
  background-size: contain;
}

#capture-ball {
  position: relative;
  width: 200px;
  height: 200px;
  background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/pkmngo-pokeball.png');
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
}

#capture-ball-button-container {
  @extend .flex-center;
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 5;
}

#capture-ball-button {
  width: 30px;
  height: 30px;
  margin-top: -20px;
  border-radius: 20px;
  opacity: 0.8;
  background-color: red;
}

#target-container {
  @extend .flex-center;
  position: relative;
}

#target {
  width: 140px;
  height: 140px;
  transform: rotate(-10deg);
  background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/pkmngo-helix.png');
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  z-index: 2;
}

#ball {
  position: fixed;
  height: 50px;
  width: 50px;
  border-radius: 25px;
  bottom: 10%;
  background-image: url('https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/pkmngo-pokeball.png');
  background-repeat: no-repeat;
  background-position: center center;
  background-size: cover;
  z-index: 3;
}

#touch-layer {
  position: fixed;
  top: 0;
  left: 0;
  opacity: 0;
  z-index: 10;
}

#capture-status {
  position: absolute;
  font-size: 1.5em;
  top: 0;
  left: 0;
  width: 100%;
  text-align: center;
  padding: 1em 0.2em;
  color: #FFF;
}

#particles {
  position: fixed;
  width: 100%;
  height: 100%;
  z-index: 1;
}

.particle {
  position: fixed;
  width: 7px;
  height: 7px;
  background-color: #fff;
  border-radius: 5px;
  opacity: 0.7;
  z-index: 1;
}

#capture-confetti {
  position: fixed;
  width: 100%;
  height: 100%;
  z-index: 6;
}

#capture-confetti> div.particle {
  height: 10px;
  width: 10px;
  opacity: 0.9;
  background-color: #4aa6fb;
}

/*Info screen*/

#info-button {
  @extend .flex-center;
  position: fixed;
  top: 5px;
  right: 5px;
  z-index: 15;
  color: button;
  width: 30px;
  height: 30px;
  color: #FFF;
  border: 2px solid #FFF;
  border-radius: 15px;
  cursor: pointer;
}

#info-screen {
  @extend .fixed-full-width;
  z-index: 14;
}

#info-shade {
  @extend .fixed-full-width;
  background-color: #222;
  opacity: 0.89;
}

#info-text {
  @extend .fixed-full-width;
  display: flex;
  flex-direction: column;
  padding: 1em;
  font-size: 0.9em;
  color: white;
}

.flex-center {
  display: flex;
  align-items: center;
  justify-content: center;
}

.fixed-full-width{
  position: fixed;
  width: 100%;
  height: 100%;
  top: 0;
  left: 0;
}

.hidden {
  display: none !important;
}


            
          
!
            
              var Screen = {
    height: window.innerHeight,
    width: window.innerWidth
};
var MAX_VELOCITY = Screen.height * 0.009;
var Resources = {
    pokeball: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/pkmngo-pokeball.png',
    pokeballActive: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/pkmngo-pokeballactive.png',
    pokeballClosed: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/374756/pkmngo-pokeballclosed.png'
};

var Ball = {
    id: 'ball',
    size: 50,
    x: 0,
    y: 0,
    inMotion: false,
    moveBall: function(x, y) {
        Ball.x = x;
        Ball.y = y;
        var BallElement = document.getElementById(Ball.id);
        BallElement.style.top = Ball.y + 'px';
        BallElement.style.left = Ball.x + 'px';
    },
    getElement() {
        return document.getElementById(Ball.id);
    },
    resetBall: function() {
        Ball.moveBall(Screen.width / 2 - (Ball.size / 2), Screen.height - (Ball.size + 10));
        var BallElement = document.getElementById(Ball.id);
        BallElement.style.transform = "";
        BallElement.style.width = BallElement.style.height = Ball.size + 'px';
        BallElement.style.backgroundImage = "url('" + Resources.pokeball + "')";
        Ball.inMotion = false;
    },
    savePosition: function() {
        var ballEle = document.getElementById('ball');
        var ballRect = ballEle.getBoundingClientRect();
        ballEle.style.transform = "";
        ballEle.style.top = ballRect.top + 'px';
        ballEle.style.left = ballRect.left + 'px';
        ballEle.style.height = ballEle.style.width = ballRect.width + 'px';
    }
};

//Initial Setup

resetState();

//Move omanyte
anime({
    targets: ['#target'],
    rotate: 20,
    duration: 800,
    loop: true,
    easing: 'easeInOutQuad',
    direction: 'alternate'
});

window.onresize = function() {
    Screen.height = window.innerHeight;
    Screen.width = window.innerWidth;
    MAX_VELOCITY = Screen.height * 0.009;
    resetState();
}


/* Gesture Bindings */
var touchElement = document.getElementById('touch-layer');
var touchRegion = new ZingTouch.Region(touchElement);
var CustomSwipe = new ZingTouch.Swipe({
    escapeVelocity: 0.1
})

var CustomPan = new ZingTouch.Pan();
var endPan = CustomPan.end;
CustomPan.end = function(inputs) {
    setTimeout(function() {
        if (Ball.inMotion === false) {
            Ball.resetBall();
        }
    }, 100);
    return endPan.call(this, inputs);
}

touchRegion.bind(touchElement, CustomPan, function(e) {
    Ball.moveBall(e.detail.events[0].x - Ball.size / 2, e.detail.events[0].y - Ball.size / 2);
});

touchRegion.bind(touchElement, CustomSwipe, function(e) {
    Ball.inMotion = true;
    var screenEle = document.getElementById('screen');
    var screenPos = screenEle.getBoundingClientRect();
    var angle = e.detail.data[0].currentDirection;
    var rawVelocity = velocity = e.detail.data[0].velocity;
    velocity = (velocity > MAX_VELOCITY) ? MAX_VELOCITY : velocity;

    //Determine the final position.
    var scalePercent = Math.log(velocity + 1) / Math.log(MAX_VELOCITY + 1);
    var destinationY = (Screen.height - (Screen.height * scalePercent)) + screenPos.top;
    var movementY = destinationY - e.detail.events[0].y;

    //Determine how far it needs to travel from the current position to the destination.
    var translateYValue = -0.75 * Screen.height * scalePercent;
    var translateXValue = 1 * (90 - angle) * -(translateYValue / 100);

    anime.remove('#ring-fill');

    anime({
            targets: ['#ball'],
            translateX: {
                duration: 300,
                value: translateXValue,
                easing: 'easeOutSine'
            },
            translateY: {
                value: movementY * 1.25 + 'px',
                duration: 300,
                easing: 'easeOutSine'
            },
            scale: {
                value: 1 - (0.5 * scalePercent),
                easing: 'easeInSine',
                duration: 300
            },
            complete: function() {
                if (movementY < 0) {
                    throwBall(movementY, translateXValue, scalePercent);
                } else {
                    setTimeout(resetState, 400);
                }
            }
        })
        //End
});

function throwBall(movementY,translateXValue, scalePercent){
    //Treat translations as fixed.
    Ball.savePosition();
    anime({
        targets: ['#ball'],
        translateY: {
            value: movementY * -0.5 + 'px',
            duration: 400,
            easing: 'easeInOutSine'
        },
        translateX: {
            value: -translateXValue * 0.25,
            duration: 400,
            easing: 'linear'
        },
        scale: {
            value: 1 - (0.25 * scalePercent),
            easing: 'easeInSine',
            duration: 400
        },
        complete: determineThrowResult
    })
}

function determineThrowResult() {
    //Determine hit-region
    var targetCoords = getCenterCoords('target');
    var ballCoords = getCenterCoords('ball');

    //Determine if the ball is touching the target.
    var radius = document.getElementById('target').getBoundingClientRect().width / 2;
    if (ballCoords.x > targetCoords.x - radius &&
        ballCoords.x < targetCoords.x + radius &&
        ballCoords.y > targetCoords.y - radius &&
        ballCoords.y < targetCoords.y + radius) {

        Ball.savePosition();
        var ballOrientation = (ballCoords.x < targetCoords.x) ? -1 : 1;
        anime({
            targets: ['#ball'],
            translateY: {
                value: -1.15 * radius,
                duration: 200,
                easing: 'linear'
            },
            translateX: {
                value: 1.15 * radius * ballOrientation,
                duration: 200,
                easing: 'linear'
            },
            scaleX: {
                value: ballOrientation,
                duration: 200,
            },
            complete: function() {
                var ball = Ball.getElement();
                ball.style.backgroundImage = "url('" + Resources.pokeballActive + "')";
                emitParticlesToPokeball();
            }
        });
    } else {
        setTimeout(resetState, 400);
    }
}


function emitParticlesToPokeball() {
    var particles = [];
    var targetEle = getCenterCoords('target');
    var ballEle = Ball.getElement();
    var ballRect = ballEle.getBoundingClientRect();
    var particleLeft;
    var particleRight;
    var palette = [
        '#E4D3A8',
        '#6EB8C0',
        '#FFF',
        '#2196F3'
    ]
    var particleContainer = document.getElementById('particles');
    for (var i = 0; i < 50; i++) {
        var particleEle = document.createElement('div');
        particleEle.className = 'particle';
        particleEle.setAttribute('id', 'particle-' + i);;
        particleLeft = getRandNum(-60, 60) + targetEle.x;
        particleEle.style.left = particleLeft + 'px';
        particleRight = getRandNum(-60, 60) + targetEle.y;
        particleEle.style.top = particleRight + 'px';
        particleEle.style.backgroundColor = palette[getRandNum(0, palette.length)]
        particleContainer.appendChild(particleEle);
        anime({
            targets: ['#particle-' + i],
            translateX: {
                value: ballRect.left - particleLeft,
                delay: 100 + (i * 10)
            },
            translateY: {
                value: ballRect.top + (Ball.size / 2) - particleRight,
                delay: 100 + (i * 10),
            },
            opacity: {
                value: 0,
                delay: 100 + (i * 10),
                duration: 800,
                easing: 'easeInSine'
            }
        });
        anime({
            targets: ['#target'],
            opacity: {
                value: 0,
                delay: 200,
                easing: 'easeInSine'
            }
        });
    }
    setTimeout(function() {
        var ball = Ball.getElement();
        ball.style.backgroundImage = "url('" + Resources.pokeballClosed + "')";
        document.getElementById('particles').innerHTML = "";
        Ball.savePosition();

        anime({
            targets: ['#ball'],
            translateY: {
                value: "200px",
                delay: 400,
                duration: 400,
                easing: 'linear'
            },
            complete: function() {
                Ball.resetBall();
            }
        });
        setTimeout(function() {
            animateCaptureState();
            resetState();
        }, 750);

    }, 1000);
}



function animateCaptureState() {
    var ballContainer = document.getElementById('capture-screen');
    ballContainer.classList.toggle('hidden');

    var duration = 500;
    anime({
        targets: ['#capture-ball'],
        rotate: 40,
        duration: duration,
        easing: 'easeInOutBack',
        loop: true,
        direction: 'alternate'
    });

    var ringRect = (document.getElementById('ring-active')).getBoundingClientRect();
    var successRate = ((150 - ringRect.width) / 150) * 100;
    var seed = getRandNum(0, 100);
    setTimeout(function() {

        anime.remove('#capture-ball');

        if (seed < Math.floor(successRate)) {
            var captureBall = document.getElementById('capture-ball');
            var buttonContainer = document.getElementById('capture-ball-button-container');
            buttonContainer.classList.toggle('hidden');

            //Captured
            var captureStatus = document.getElementById('capture-status');
            captureStatus.classList.toggle('hidden');
            captureStatus.innerHTML = "You caught Omanyte!"
            makeItRainConfetti();

            anime({
                targets: ['#capture-ball-button-container'],
                opacity: {
                    value: 0,
                    duration: 800,
                    easing: 'easeInSine'
                },
                complete: function() {
                    setTimeout(function() {
                        var ballContainer = document.getElementById('capture-screen');
                        ballContainer.classList.toggle('hidden');
                        var buttonContainer = document.getElementById('capture-ball-button-container');
                        buttonContainer.classList.toggle('hidden');
                        buttonContainer.style.opacity = "";
                        document.getElementById('capture-status').classList.toggle('hidden');
                    }, 800);
                }
            });

        } else {
            var poofContainer = document.getElementById('poof-container');
            poofContainer.classList.toggle('hidden');

            var captureStatus = document.getElementById('capture-status');
            captureStatus.innerHTML = "Omanyte Escaped!"
            captureStatus.classList.toggle('hidden');

            anime({
                targets: ['#poof'],
                scale: {
                    value: 20,
                    delay: 400,
                    easing: 'linear',
                    duration: 600
                },
                complete: function() {
                    var ballContainer = document.getElementById('capture-screen');
                    ballContainer.classList.toggle('hidden');

                    var poofEle = document.getElementById('poof');
                    poofEle.style.transform = "";
                    var poofContainer = document.getElementById('poof-container');
                    poofContainer.classList.toggle('hidden');

                    var captureStatus = document.getElementById('capture-status');
                    captureStatus.classList.toggle('hidden');
                }
            })
        }
    }, duration * 6);

}


function makeItRainConfetti() {
    for (var i = 0; i < 100; i++) {
        var particleContainer = document.getElementById('capture-confetti');
        var particleEle = document.createElement('div');
        particleEle.className = 'particle';
        particleEle.setAttribute('id', 'particle-' + i);
        particleLeft = window.innerWidth / 2;
        particleEle.style.left = particleLeft + 'px';
        particleTop = window.innerHeight / 2;
        particleEle.style.top = particleTop + 'px';
        particleEle.style.backgroundColor = ((getRandNum(0, 2)) ? '#FFF' : '#4aa6fb')
        particleContainer.appendChild(particleEle);
        anime({
            targets: ['#particle-' + i],
            translateX: {
                value: ((getRandNum(0, 2)) ? -1 : 1) * getRandNum(0, window.innerWidth / 2),
                delay: 100
            },
            translateY: {
                value: ((getRandNum(0, 2)) ? -1 : 1) * getRandNum(0, window.innerHeight / 2),
                delay: 100,
            },
            opacity: {
                value: 0,
                duration: 800,
                easing: 'easeInSine'
            },
            complete: function() {
                document.getElementById('capture-confetti').innerHTML = "";
            }
        });
    }
}

function toggleInfoScreen() {
    var infoScreen = document.getElementById('info-screen');
    var infoButton = document.getElementById('info-button');
    infoScreen.classList.toggle('hidden');
    infoButton.innerHTML = (infoScreen.className === 'hidden') ? "?" : 'X';
}

/* * * * * * * * * * * * *
* Universal Helpers
* * * * * * * * * * * * */
function resetState() {
    Ball.resetBall();
    document.getElementById('target').style.opacity = 1;
    //Adjust Ring
    var ring = document.getElementById('ring-fill');
    ring.style.height = "150px";
    ring.style.width = "150px";
    anime({
        targets: ['#ring-fill'],
        height: "5px",
        width: "5px",
        duration: 3000,
        loop: true,
        easing: 'linear'
    })
}

function getCenterCoords(elementId) {
    var rect = document.getElementById(elementId).getBoundingClientRect();
    return {
        x: rect.left + rect.width / 2,
        y: rect.top + rect.height / 2
    };
}

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

            
          
!
999px
Close

Asset uploading is a PRO feature.

As a PRO member, you can drag-and-drop upload files here to use as resources. Images, Libraries, JSON data... anything you want. You can even edit them anytime, like any other code on CodePen.

Go PRO

Loading ..................

Console