Pen Settings

HTML

CSS

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. You can use the CSS from another Pen by using it's URL and the proper URL extention.

+ 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

              
                <p class="description">
  <span id="pun"></span>
</p>

<div class="collection"><p> Hacé Click para atraer más seguridad, educación y fortuna!</p></div>


              
            
!

CSS

              
                
.description {
  position: fixed;
  bottom: 0;
  color: #4A5568;
  z-index: 100;
  margin: 40px;
  font-family: 'Montserrat', sans-serif;

}


* {
  margin: 0;
}

html, body {
  cursor: pointer;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

canvas {
  display: block;
  overflow: hidden;
}

.collection {
  position: fixed;
  z-index: 1000;
  width: auto;
  bottom: 0;
  justify-content: left;
  right: 0;
  margin: 10px;
  padding: 0;
  font-size: 12px;
  color: #719999;
}

.collection a {
  display: inline-block;
  background: #fff;
  opacity: 0.4;
  transition: opacity 0.7s;
  margin-left: 5px;
  padding: 5px;
  text-decoration: none;
  font-weight: bold;
  color: #ffffff;
}

.collection a:hover {
  opacity: 1;
}

a:link {
  color: #ffffff;
  background-color: transparent;
  text-decoration: underline;
}

a:visited {
  color: #FFC904;
  background-color: transparent;
  text-decoration: underline;
}

a:hover {
  color: #2B6CB0;
  background-color: transparent;
  text-decoration: underline;
}

a:active {
  color: #0693E3;
  background-color: transparent;
  text-decoration: underline;
}

              
            
!

JS

              
                
var punArray = ["<a href='https://cibersergei.com/protegete-y-protege-tu-informacion/' target='_blank'>Protégete y protegé tu información</a>","<a href='https://cibersergei.com/escucha-mejor/' target='_blank'>Escuchá mejor</a>","<a href='https://cibersergei.com/denuncia-un-incidente/' target='_blank'>Denunciá un incidente</a>", "<a href='https://cibersergei.com/juga-mas/' target='_blank'>Jugá más</a>", "<a href='https://cibersergei.com/enfoca-en-lo-esencial/' target='_blank'>Enfocá en lo esencial</a>", "<a href='https://cibersergei.com/revisa-tus-contrasenas/' target='_blank'>Revisá tus contraseñas</a>", "<a href='https://cibersergei.com/aprende-seguridad-siempre/' target='_blank'>Aprendé seguridad siempre</a>", "<a href='https://cibersergei.com/presta-atencion-a-una-sola-cosa-a-la-vez/' target='_blank'>Prestá atención a una sola cosa a la vez</a>", "<a href='https://cibersergei.com/actualiza-tu-software/' target='_blank'>Actualizá tu software</a>", "<a href='https://cibersergei.com/rodeate-de-inspiracion/' target='_blank'>Rodéate de inspiración</a>", "<a href='https://cibersergei.com/el-proceso-de-aprendizaje-es-mutuo/' target='_blank'>El proceso de aprendizaje es mútuo</a>", "<a href='https://cibersergei.com/comparti-lo-que-sabes/' target='_blank'>Compartí lo que sabes</a>", "<a href='https://cibersergei.com/practica-y-entrena-lo-que-has-aprendido/' target='_blank'>Practicá y entrená lo que has aprendido</a>", "<a href='https://cibersergei.com/actualiza-periodicamente-tus-navegadores/' target='_blank'>Actualizá periódicamente tus navegadores</a>", "<a href='https://cibersergei.com/sali-de-tu-zona-de-confort/' target='_blank'>Salí de tu zona de confort</a>", "<a href='https://cibersergei.com/asegura-tus-redes/' target='_blank'>Asegurá tus redes</a>", "<a href='https://cibersergei.com/pausa-y-recarga-energias/' target='_blank'>Pausá y recargá energías</a>", "<a href='https://cibersergei.com/protegete-del-ransomware/' target='_blank'>Protégete del Ransomware</a>", "<a href='https://cibersergei.com/utiliza-tus-superpoderes/' target='_blank'>Utilizá tus superpoderes</a>", "<a href='https://cibersergei.com/no-confies-en-nadie/' target='_blank'>No confíes en nadie</a>", "<a href='https://cibersergei.com/sonrie-muchas-veces-al-dia/' target='_blank'>Sonríe muchas veces al día</a>", "<a href='https://cibersergei.com/protegete-contra-el-robo-de-identidad/' target='_blank'>Protégete contra el robo de identidad</a>", "<a href='https://cibersergei.com/la-seguridad-te-da-confianza/' target='_blank'>La Seguridad te da Confianza</a>", "<a href='https://cibersergei.com/es-posible-alcanzar-largas-distancias-solo-superando-distancias-cortas/' target='_blank'>Es posible alcanzar largas distancias solo superando distancias cortas</a>", "<a href='https://cibersergei.com/bloquearlo/' target='_blank'>Bloquearlo</a>", "<a href='https://cibersergei.com/conectate-con-la-naturaleza/' target='_blank'>Conéctate con la naturaleza</a>", "<a href='https://cibersergei.com/hazte-amigo-de-un-nuevo-consejo-de-seguridad/' target='_blank'>Hazte amigo de un nuevo consejo de seguridad</a>", "<a href='https://cibersergei.com/encontra-poder-en-el-silencio/' target='_blank'>Encontrá poder en el silencio</a>", "<a href='https://cibersergei.com/a-donde-van-tus-datos/' target='_blank'>¿A dónde van tus datos?</a>", "<a href='https://cibersergei.com/realiza-preguntas-para-revelar-historias/' target='_blank'>Realizá preguntas para revelar historias</a>", "<a href='https://cibersergei.com/protege-tus-sistemas/' target='_blank'>Protegé tus sistemas</a>", "<a href='https://cibersergei.com/desaprende-algo-que-ya-sabes/' target='_blank'>Desaprendé algo que ya sabes</a>", "<a href='https://cibersergei.com/configura-alertas-de-fraude/' target='_blank'>Configurá alertas de fraude</a>", "<a href='https://cibersergei.com/cambia-de-perspectiva/' target='_blank'>Cambiá de perspectiva</a>", "<a href='https://cibersergei.com/configura-un-segundo-factor-de-autenticacion-2fa/' target='_blank'>Configurá un Segundo Factor de Autenticación (2FA)</a>", "<a href='https://cibersergei.com/concentrate-en-lo-que-puedes-controlar/' target='_blank'>Concéntrate en lo que puedes controlar</a>", "<a href='https://cibersergei.com/protege-tus-tarjetas-de-pago/' target='_blank'>Protegé tus tarjetas de pago</a>", "<a href='https://cibersergei.com/desarrolla-una-mentalidad-de-seguridad/' target='_blank'>Desarrollá una mentalidad de seguridad</a>", "<a href='https://cibersergei.com/resolve-conflictos/' target='_blank'>Resolvé conflictos</a>", "<a href='https://cibersergei.com/limpia-tus-aplicaciones/' target='_blank'>Limpiá tus aplicaciones</a>", "<a href='https://cibersergei.com/se-perseverante/' target='_blank'>Sé perseverante</a>", "<a href='https://cibersergei.com/desactiva-la-conexion-automatica/' target='_blank'>Desactivá la conexión automática</a>", "<a href='https://cibersergei.com/enfrentate-a-los-desafios/' target='_blank'>Enfréntate a los desafíos</a>", "<a href='https://cibersergei.com/controla-el-acceso-a-la-aplicacion/' target='_blank'>Controla el acceso a la aplicación</a>", "<a href='https://cibersergei.com/crea-oportunidades/' target='_blank'>Creá oportunidades</a>", "<a href='https://cibersergei.com/se-cauteloso/' target='_blank'>Sé cauteloso</a>", "<a href='https://cibersergei.com/cuidate-a-ti-mismo/' target='_blank'>Cuídate a ti mismo</a>", "<a href='https://cibersergei.com/realiza-una-copia-de-seguridad-de-tus-datos/' target='_blank'>Realizá una copia de seguridad de tus datos</a>", "<a href='https://cibersergei.com/planifica/' target='_blank'>Planificá</a>", "<a href='https://cibersergei.com/revisa-tus-cuentas-de-email/' target='_blank'>Revisá tus cuentas de email</a>", "<a href='https://cibersergei.com/aprovecha-el-presente/' target='_blank'>Aprovechá el presente</a>", "<a href='https://cibersergei.com/crea-una-identidad-alternativa/' target='_blank'>Creá una identidad alternativa</a>", "<a href='https://cibersergei.com/la-concentracion-es-tu-puerta-de-entrada-al-pensamiento-y-proteccion/' target='_blank'>La concentración es tu puerta de entrada al pensamiento y protección</a>", "<a href='https://cibersergei.com/protege-lo-que-mas-te-importa/' target='_blank'>Protege lo que más te importa</a>", "<a href='https://cibersergei.com/entrena-tu-cerebro-como-un-musculo/' target='_blank'>Entrená tu cerebro como un músculo</a>", "<a href='https://cibersergei.com/utiliza-vpn-para-ocultar-tu-actividad-en-linea/' target='_blank'>Utiliza VPN para ocultar tu actividad en línea</a>", "<a href='https://cibersergei.com/utiliza-tu-propia-lupa/' target='_blank'>Utiliza tu propia lupa</a>", "<a href='https://cibersergei.com/familiarizate-con-las-regulaciones-de-seguridad-y-privacidad/' target='_blank'>Familiarizate con las Regulaciones de Seguridad y Privacidad</a>", "<a href='https://cibersergei.com/el-cambio-es-un-principio-de-armonia/' target='_blank'>El cambio es un principio de armonía</a>", "<a href='https://cibersergei.com/destruye-la-informacion-que-ya-no-necesitas/' target='_blank'>Destruye la información que ya no necesitas</a>", "<a href='https://cibersergei.com/determina-tus-prioridades/' target='_blank'>Determina tus prioridades</a>", "<a href='https://cibersergei.com/protege-tu-red-wifi/' target='_blank'>Protege tu red WiFi</a>", "<a href='https://cibersergei.com/busca-ser-mas-flexible/' target='_blank'>Busca ser más flexible</a>", "<a href='https://cibersergei.com/aprovecha-las-pautas-de-seguridad-de-tu-organizacion/' target='_blank'>Aprovecha las pautas de seguridad de tu organización</a>", "<a href='https://cibersergei.com/mantente-conectado-desconectandote/' target='_blank'>Mantente conectado desconectándote</a>", "<a href='https://cibersergei.com/borra-las-conversaciones-grabadas-en-tus-dispositivos/' target='_blank'>Borra las conversaciones grabadas en tus dispositivos</a>", "<a href='https://cibersergei.com/aprende-algo-complejo-antes-de-dormir/' target='_blank'>Aprende algo complejo antes de dormir</a>", "<a href='https://cibersergei.com/protegete-del-vishing/' target='_blank'>Protégete del Vishing</a>", "<a href='https://cibersergei.com/no-hagas-click-en-enlaces-de-fuentes-sospechosas/' target='_blank'>No hagás click en enlaces de fuentes sospechosas</a>", "<a href='https://cibersergei.com/evita-las-distracciones/' target='_blank'>Evita las distracciones</a>"];

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

const vertexShader = `
#ifdef GL_ES
precision highp float;
#endif

attribute vec3 position;
attribute vec2 uv;

uniform mat4 projectionMatrix;
uniform mat4 modelViewMatrix;

varying vec2 vUv;

void main(){
    vUv = uv;
    gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0);
}
`;
const fragmentShader = `
#ifdef GL_ES
precision highp float;
#endif

varying vec2 vUv;

uniform sampler2D texture;
uniform float uOpacity;

void main(){
    if(uOpacity == 0.0) discard;
    gl_FragColor = texture2D(texture, vUv);
    if(gl_FragColor.a == 0.0) discard;
    gl_FragColor.a *= uOpacity;

}`;

var coinData = {
  pivot: [40, 260],
  imgName: 'coin',
  positionArray: [-32, 32, 0, -16, 32, 0, 0, 32, 0, 16, 32, 0, 32, 32, 0, -32, 16, 0, -16, 16, 0, 0, 16, 0, 16, 16, 0, 32, 16, 0, -32, 0, 0, -16, 0, 0, 0, 0, 0, 16, 0, 0, 32, 0, 0, -32, -16, 0, -16, -16, 0, 0, -16, 0, 16, -16, 0, 32, -16, 0, -32, -32, 0, -16, -32, 0, 0, -32, 0, 16, -32, 0, 32, -32, 0],
  uvArray: [0, 1, 0.25, 1, 0.5, 1, 0.75, 1, 1, 1, 0, 0.75, 0.25, 0.75, 0.5, 0.75, 0.75, 0.75, 1, 0.75, 0, 0.5, 0.25, 0.5, 0.5, 0.5, 0.75, 0.5, 1, 0.5, 0, 0.25, 0.25, 0.25, 0.5, 0.25, 0.75, 0.25, 1, 0.25, 0, 0, 0.25, 0, 0.5, 0, 0.75, 0, 1, 0],
  indexArray: [0, 1, 5, 1, 6, 5, 1, 2, 6, 2, 7, 6, 2, 3, 7, 3, 8, 7, 3, 4, 8, 4, 9, 8, 5, 6, 10, 6, 11, 10, 6, 7, 11, 7, 12, 11, 7, 8, 12, 8, 13, 12, 8, 9, 13, 9, 14, 13, 10, 11, 15, 11, 16, 15, 11, 12, 16, 12, 17, 16, 12, 13, 17, 13, 18, 17, 13, 14, 18, 14, 19, 18, 15, 16, 20, 16, 21, 20, 16, 17, 21, 17, 22, 21, 17, 18, 22, 18, 23, 22, 18, 19, 23, 19, 24, 23],
  neighborArray: [[1, 5], [0, 2, 5, 6], [1, 3, 6, 7], [2, 4, 7, 8], [3, 8, 9], [0, 1, 6, 10], [0, 1, 2, 5, 7, 10, 11], [1, 2, 3, 6, 8, 11, 12], [2, 3, 4, 7, 9, 12, 13], [3, 4, 8, 13, 14], [5, 6, 11, 15], [5, 6, 7, 10, 12, 15, 16], [6, 7, 8, 11, 13, 16, 17], [7, 8, 9, 12, 14, 17, 18], [8, 9, 13, 18, 19], [10, 11, 16, 20], [10, 11, 12, 15, 17, 20, 21], [11, 12, 13, 16, 18, 21, 22], [12, 13, 14, 17, 19, 22, 23], [13, 14, 18, 23, 24], [15, 16, 21], [15, 16, 17, 20, 22], [16, 17, 18, 21, 23], [17, 18, 19, 22, 24], [18, 19, 23]],
  selectionArea: [{ x: 0, y: 24, width: 64, height: 16 }, { x: 0, y: 8, width: 64, height: 16 }, { x: 0, y: -8, width: 64, height: 16 }, { x: 0, y: -24, width: 64, height: 16 }] };


var magnetData = {
  pivot: [140, 60],
  imgName: 'magnet',
  positionArray: [-151.5, 72, 0, -111.5, 72, 0, -71.5, 72, 0, -31.5, 72, 0, 8.5, 72, 0, 48.5, 72, 0, 88.5, 72, 0, 128.5, 72, 0, 168.5, 72, 0, -151.5, 32, 0, -111.5, 32, 0, -71.5, 32, 0, -31.5, 32, 0, 8.5, 32, 0, 48.5, 32, 0, 88.5, 32, 0, 128.5, 32, 0, 168.5, 32, 0, -151.5, -8, 0, -111.5, -8, 0, -71.5, -8, 0, -31.5, -8, 0, 8.5, -8, 0, 48.5, -8, 0, 88.5, -8, 0, 128.5, -8, 0, 168.5, -8, 0, -151.5, -48, 0, -111.5, -48, 0, -71.5, -48, 0, -31.5, -48, 0, 8.5, -48, 0, 48.5, -48, 0, 88.5, -48, 0, 128.5, -48, 0, 168.5, -48, 0, -151.5, -88, 0, -111.5, -88, 0, -71.5, -88, 0, -31.5, -88, 0, 8.5, -88, 0, 48.5, -88, 0, 88.5, -88, 0, 128.5, -88, 0, 168.5, -88, 0],
  uvArray: [0, 1, 0.132013201320132, 1, 0.264026402640264, 1, 0.39603960396039606, 1, 0.528052805280528, 1, 0.6600660066006601, 1, 0.7920792079207921, 1, 0.9240924092409241, 1, 1.056105610561056, 1, 0, 0.7222222222222222, 0.132013201320132, 0.7222222222222222, 0.264026402640264, 0.7222222222222222, 0.39603960396039606, 0.7222222222222222, 0.528052805280528, 0.7222222222222222, 0.6600660066006601, 0.7222222222222222, 0.7920792079207921, 0.7222222222222222, 0.9240924092409241, 0.7222222222222222, 1.056105610561056, 0.7222222222222222, 0, 0.4444444444444444, 0.132013201320132, 0.4444444444444444, 0.264026402640264, 0.4444444444444444, 0.39603960396039606, 0.4444444444444444, 0.528052805280528, 0.4444444444444444, 0.6600660066006601, 0.4444444444444444, 0.7920792079207921, 0.4444444444444444, 0.9240924092409241, 0.4444444444444444, 1.056105610561056, 0.4444444444444444, 0, 0.16666666666666663, 0.132013201320132, 0.16666666666666663, 0.264026402640264, 0.16666666666666663, 0.39603960396039606, 0.16666666666666663, 0.528052805280528, 0.16666666666666663, 0.6600660066006601, 0.16666666666666663, 0.7920792079207921, 0.16666666666666663, 0.9240924092409241, 0.16666666666666663, 1.056105610561056, 0.16666666666666663, 0, -0.11111111111111116, 0.132013201320132, -0.11111111111111116, 0.264026402640264, -0.11111111111111116, 0.39603960396039606, -0.11111111111111116, 0.528052805280528, -0.11111111111111116, 0.6600660066006601, -0.11111111111111116, 0.7920792079207921, -0.11111111111111116, 0.9240924092409241, -0.11111111111111116, 1.056105610561056, -0.11111111111111116],
  indexArray: [0, 1, 9, 1, 10, 9, 1, 2, 10, 2, 11, 10, 2, 3, 11, 3, 12, 11, 3, 4, 12, 4, 13, 12, 4, 5, 13, 5, 14, 13, 5, 6, 14, 6, 15, 14, 6, 7, 15, 7, 16, 15, 7, 8, 16, 8, 17, 16, 9, 10, 18, 10, 19, 18, 10, 11, 19, 11, 20, 19, 11, 12, 20, 12, 21, 20, 12, 13, 21, 13, 22, 21, 13, 14, 22, 14, 23, 22, 14, 15, 23, 15, 24, 23, 15, 16, 24, 16, 25, 24, 16, 17, 25, 17, 26, 25, 18, 19, 27, 19, 28, 27, 19, 20, 28, 20, 29, 28, 20, 21, 29, 21, 30, 29, 21, 22, 30, 22, 31, 30, 22, 23, 31, 23, 32, 31, 23, 24, 32, 24, 33, 32, 24, 25, 33, 25, 34, 33, 25, 26, 34, 26, 35, 34, 27, 28, 36, 28, 37, 36, 28, 29, 37, 29, 38, 37, 29, 30, 38, 30, 39, 38, 30, 31, 39, 31, 40, 39, 31, 32, 40, 32, 41, 40, 32, 33, 41, 33, 42, 41, 33, 34, 42, 34, 43, 42, 34, 35, 43, 35, 44, 43],
  neighborArray: [[1, 9], [0, 2, 9, 10], [1, 3, 10, 11], [2, 4, 11, 12], [3, 5, 12, 13], [4, 6, 13, 14], [5, 7, 14, 15], [6, 8, 15, 16], [7, 16, 17], [0, 1, 10, 18], [0, 1, 2, 9, 11, 18, 19], [1, 2, 3, 10, 12, 19, 20], [2, 3, 4, 11, 13, 20, 21], [3, 4, 5, 12, 14, 21, 22], [4, 5, 6, 13, 15, 22, 23], [5, 6, 7, 14, 16, 23, 24], [6, 7, 8, 15, 17, 24, 25], [7, 8, 16, 25, 26], [9, 10, 19, 27], [9, 10, 11, 18, 20, 27, 28], [10, 11, 12, 19, 21, 28, 29], [11, 12, 13, 20, 22, 29, 30], [12, 13, 14, 21, 23, 30, 31], [13, 14, 15, 22, 24, 31, 32], [14, 15, 16, 23, 25, 32, 33], [15, 16, 17, 24, 26, 33, 34], [16, 17, 25, 34, 35], [18, 19, 28, 36], [18, 19, 20, 27, 29, 36, 37], [19, 20, 21, 28, 30, 37, 38], [20, 21, 22, 29, 31, 38, 39], [21, 22, 23, 30, 32, 39, 40], [22, 23, 24, 31, 33, 40, 41], [23, 24, 25, 32, 34, 41, 42], [24, 25, 26, 33, 35, 42, 43], [25, 26, 34, 43, 44], [27, 28, 37], [27, 28, 29, 36, 38], [28, 29, 30, 37, 39], [29, 30, 31, 38, 40], [30, 31, 32, 39, 41], [31, 32, 33, 40, 42], [32, 33, 34, 41, 43], [33, 34, 35, 42, 44], [34, 35, 43]],
  selectionArea: [{ x: 8.5, y: 52, width: 320, height: 40 }, { x: 8.5, y: 12, width: 320, height: 40 }, { x: 8.5, y: -28, width: 320, height: 40 }, { x: 8.5, y: -68, width: 320, height: 40 }] };


/**
* PhysicsPoint
*/

function PhysicsPoint(params) {
  THREE.EventDispatcher.call(this);

  this.isStatic = params.isStatic;

  this.baseOriginalPhysicsPoint = new THREE.Vector3(params.x, params.y, 0);
  this.originalPhysicsPoint = new THREE.Vector2(params.x, params.y);
  this.point = this.originalPhysicsPoint.clone();
  this.pivotPt = params.pivotPt;

  // this.updateParameter();
  if (params.distanceType === 'x') this._calculateDistanceFromPivotX();else
  if (params.distanceType === 'y') this._calculateDistanceFromPivotY();else
  this._calculateDistanceFromPivot();

  this.maxDistancefromPivot = 500;
  this.origK = 2;
  this.k = this.origK;
  this.origInitK = 5;
  this.initK = this.origInitK;
  this.step = 0;
  this.dampingC = 0.98;

  this.velocity = new THREE.Vector2();
  this.neighbors = params.neighbors ? params.neighbors : [];
}

PhysicsPoint.prototype = Object.create(THREE.EventDispatcher.prototype);
PhysicsPoint.prototype.constructor = PhysicsPoint;

_.extend(PhysicsPoint.prototype, {
  _calculateDistanceFromPivot: function () {
    this.distanceFromPivot = this.pivotPt.distanceTo(this.baseOriginalPhysicsPoint);
  },
  _calculateDistanceFromPivotX: function () {
    this.distanceFromPivot = Math.abs(this.pivotPt.x - this.baseOriginalPhysicsPoint.x);
  },
  _calculateDistanceFromPivotY: function () {
    this.distanceFromPivot = Math.abs(this.pivotPt.y - this.baseOriginalPhysicsPoint.y);
  },
  updateParameter: function (maxDistancefromPivot) {
    this.maxDistancefromPivot = maxDistancefromPivot;

    var distanceRate = THREE.Math.clamp(this.distanceFromPivot / this.maxDistancefromPivot, 0, 1);
    this.k = this.origK; // this.origK * distanceRate;
    this.initK = this.origInitK; // this.origInitK;// * distanceRate;
    this.step = distanceRate * 0.3 + 0.5;
    this.dampingC = 0.01; //0.80 + (distanceRate) * 0.15;
    this.distanceRate = distanceRate;
  },
  updateOrigin: function (angularMatrix) {
    if (angularMatrix && angularMatrix.matrix) {
      var targetPt = this.baseOriginalPhysicsPoint.clone().applyMatrix4(angularMatrix.matrix);
      this.originalPhysicsPoint.set(
      this.baseOriginalPhysicsPoint.x * (1 - this.distanceRate) + targetPt.x * this.distanceRate,
      this.baseOriginalPhysicsPoint.y * (1 - this.distanceRate) + targetPt.y * this.distanceRate);

    }
  },
  rollover: function () {
    com.gstar.TweenMax.to(this.velocity, 0.4, { x: 0, y: 0 });
    com.gstar.TweenMax.to(this.point, 0.4, { x: this.baseOriginalPhysicsPoint.x, y: this.baseOriginalPhysicsPoint.y });
  },
  update: function (delta) {
    if (this.isStatic) return;
    delta = delta ? delta : 1 / 60;

    var f0;

    this.point.x = (this.originalPhysicsPoint.x - this.point.x) * this.step + this.point.x;
    this.point.y = (this.originalPhysicsPoint.y - this.point.y) * this.step + this.point.y;

    var oriDir = this.point.clone().sub(this.originalPhysicsPoint);
    var oriDirDis = oriDir.length();
    if (oriDirDis > 0) f0 = oriDir.normalize().multiplyScalar(-this.initK * oriDirDis);else
    f0 = new THREE.Vector2();

    for (var ii = 0; ii < this._neighborPoints.length; ii++) {if (window.CP.shouldStopExecution(0)) break;
      var neighborPt = this._neighborPoints[ii].pt;
      var orignalDistance = this._neighborPoints[ii].originalDistance;
      var curDirection = this.point.clone().sub(neighborPt.point);
      var curDistance = curDirection.length();
      var force = curDirection.normalize().multiplyScalar(-this.k * (curDistance - orignalDistance));
      f0.add(force);
    }window.CP.exitedLoop(0);


    this.velocity.x *= 0.92;
    this.velocity.y *= 0.92;
    f0.addScaledVector(this.velocity, -this.dampingC);

    this.velocity.addScaledVector(f0, delta);
    this.point.addScaledVector(this.velocity, delta);
  },
  updateNeighbors: function (points) {
    this._points = points;
    this._neighborPoints = [];

    for (var ii = 0; ii < this.neighbors.length; ii++) {if (window.CP.shouldStopExecution(1)) break;
      var targetPt = this._points[this.neighbors[ii]];
      var originaVec = targetPt.originalPhysicsPoint.clone().sub(this.originalPhysicsPoint);
      var originalDistance = originaVec.length();
      this._neighborPoints.push({ pt: targetPt, originalDistance: originalDistance });
    }window.CP.exitedLoop(1);
  },
  debugCanvasDraw: function (ctx) {
    ctx.strokeStyle = '#ffffff';

    // console.log(this._neighborPoints);
    for (var ii = 0; ii < this._neighborPoints.length; ii++) {if (window.CP.shouldStopExecution(2)) break;
      // var ii = 1;
      var neighborPt = this._neighborPoints[ii].pt;

      ctx.beginPath();
      ctx.moveTo(this.point.x, this.point.y);
      ctx.lineTo(neighborPt.point.x, neighborPt.point.y);
      ctx.stroke();
    }window.CP.exitedLoop(2);

  } });



/**
*   ========================
*         AngularMatrix
*   ========================
*/


function AngularMatrix(isTHREEJs) {
  this.center = new THREE.Vector3();
  this.angle = 0;
  this.angleVel = 0;
  this.angDumping = 0.8;
  this.angVelDumping = 0.8;

  this.minAngle = -15 / 180 * Math.PI;
  this.maxAngle = 15 / 180 * Math.PI;

  this.isTHREEJs = isTHREEJs;
  if (isTHREEJs) this.dir = -1;else
  this.dir = 1;
}

AngularMatrix.prototype = {
  _updateAngleVelocity: function (delta, mouseVelocity, scrollVelocity, rotationVelocity) {
    var force;
    force = (mouseVelocity.x + mouseVelocity.y) * 15;
    // if(force > 1) force = 1;
    // else if(force < -1) force = -1;
    this.angleVel += force * delta;
  },
  rollover: function () {
    com.gstar.TweenMax.to(this, 0.5, { angle: 0, angleVel: 0 });
  },
  update: function (delta, mouseVelocity, scrollVelocity, rotationVelocity) {
    // if(scrollVelocity!=0) console.log(scrollVelocity);
    if (mouseVelocity) this._updateAngleVelocity(delta, mouseVelocity, scrollVelocity, rotationVelocity);

    this.angleVel *= this.angVelDumping;
    this.angle += this.angleVel * delta;
    this.angle *= this.angDumping;

    if (this.angle < this.minAngle) {
      var dAngle = this.minAngle - this.angle;
      this.angleVel += dAngle * 0.05;
      this.angle += dAngle * 0.1;
    }

    if (this.angle > this.maxAngle) {
      var dAngle = this.maxAngle - this.angle;
      this.angle += dAngle * 0.1;
      this.angleVel += dAngle * 0.05;
    }

    var matrix0 = new THREE.Matrix4();
    var matrix1 = new THREE.Matrix4();
    var matrix = new THREE.Matrix4();

    matrix0.makeTranslation(-this.center.x, -this.center.y, 0);
    matrix1.makeRotationZ(this.angle);
    matrix.makeTranslation(this.center.x, this.center.y, 0);

    matrix.multiply(matrix1).multiply(matrix0);

    this.matrix = matrix;
  },

  debugDraw: function (ctx) {
    ctx.strokeStyle = '#00ff00';
    ctx.beginPath();
    ctx.arc(this.center.x, this.dir * this.center.y, 5, 0, Math.PI * 2);
    ctx.closePath();
    ctx.stroke();

    ctx.beginPath();
    ctx.fillStyle = '#00ff00';
    ctx.arc(this.center.x, this.dir * this.center.y, 2, 0, Math.PI * 2);
    ctx.closePath();
    ctx.fill();
  },
  updateCenter: function (xx, yy) {
    this.center.x = xx;
    this.center.y = yy;
  } };




/**
*   ========================
*       PuppetObject3D
*   ========================
*/

function PuppetObject3D(params) {
  THREE.Object3D.call(this);

  params = params ? params : {};

  this.positionArray = params.positionArray;
  this.uvArray = params.uvArray;
  this.indexArray = params.indexArray;
  this.neighborArray = params.neighborArray;
  this.pivotPt = params.pivotPt ? params.pivotPt : new THREE.Vector3();

  this._isDebug = !!params.isDebug;

  this.bufGeometry = new THREE.BufferGeometry();

  this._setBufferGeometry();
  this._setUpPhysics(params.distanceType);
  this._connectionMargin = 5;
  if (params.connections) this._setUpConnectionPoints(params.connections);


  this.material = new THREE.RawShaderMaterial({
    side: THREE.DoubleSide,
    uniforms: {
      texture: { value: params.texture },
      uOpacity: { value: 1 } },

    transparent: true,
    vertexShader: vertexShader,
    fragmentShader: fragmentShader });


  this.puppetMesh = new THREE.Mesh(this.bufGeometry, this.material);

  this.add(this.puppetMesh);

  this.connected = { left: null, right: null };

  if (this._isDebug) this._setDebug();
}

PuppetObject3D.prototype = Object.create(THREE.Object3D.prototype);
PuppetObject3D.prototype.constructor = PuppetObject3D;

_.extend(PuppetObject3D.prototype, {
  _setBufferGeometry: function () {
    this.positionAttribute = new THREE.BufferAttribute(new Float32Array(this.positionArray), 3);
    this.bufGeometry.addAttribute('position', this.positionAttribute);
    this.bufGeometry.addAttribute('uv', new THREE.BufferAttribute(new Float32Array(this.uvArray), 2));
    this.bufGeometry.setIndex(new THREE.BufferAttribute(new Uint16Array(this.indexArray), 1));
  },
  _setUpPhysics: function (distanceType) {
    this.physicsPoints = [];

    this.angularMatrix = new AngularMatrix(true);
    this.angularMatrix.updateCenter(this.pivotPt.x, this.pivotPt.y);

    var maxDistanceFromPvot = -9999;
    for (var ii = 0; ii < this.positionArray.length; ii += 3) {if (window.CP.shouldStopExecution(3)) break;
      var physicsPoint = new PhysicsPoint({ x: this.positionArray[ii], y: this.positionArray[ii + 1], neighbors: this.neighborArray[ii / 3], pivotPt: this.pivotPt, distanceType: distanceType });
      this.physicsPoints.push(physicsPoint);
      if (maxDistanceFromPvot < physicsPoint.distanceFromPivot) maxDistanceFromPvot = physicsPoint.distanceFromPivot;
    }window.CP.exitedLoop(3);

    for (var ii = 0; ii < this.physicsPoints.length; ii++) {if (window.CP.shouldStopExecution(4)) break;
      this.physicsPoints[ii].updateParameter(maxDistanceFromPvot);
      this.physicsPoints[ii].updateNeighbors(this.physicsPoints);
    }window.CP.exitedLoop(4);
  },
  _setDebug: function () {
    var mat = new THREE.MeshBasicMaterial({
      color: 0xffffff,
      wireframe: true });

    this._debugMesh = new THREE.Mesh(this.bufGeometry, mat);
    this._debugMesh.position.z = 1;
    this.add(this._debugMesh);
  },
  _setUpConnectionPoints: function (connections) {
    this._leftNumber = connections.left;
    this._rightNumber = connections.right;

    if (this._isDebug) {

      if (this._leftNumber) {
        this._leftDebugMesh = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), new THREE.MeshBasicMaterial({
          color: 0xff0000,
          wireframe: true }));

        this._leftDebugMesh.position.z = 1;
        this.add(this._leftDebugMesh);
      }

      if (this._rightNumber) {
        this._rightDebugMesh = new THREE.Mesh(new THREE.PlaneGeometry(10, 10), new THREE.MeshBasicMaterial({
          color: 0x00ff00,
          wireframe: true }));

        this._rightDebugMesh.position.z = 1;
        this.add(this._rightDebugMesh);
      }

    }
  },
  _calcalteConnectionPoint: function (sideNumber) {
    var pointX, pointY;
    var pt = new THREE.Vector2();

    if (sideNumber.numArray) {
      var rate = sideNumber.rate;
      pointX = (1 - rate) * this.physicsPoints[sideNumber.numArray[0]].point.x + rate * this.physicsPoints[sideNumber.numArray[1]].point.x;
      pointY = (1 - rate) * this.physicsPoints[sideNumber.numArray[0]].point.y + rate * this.physicsPoints[sideNumber.numArray[1]].point.y;
    } else {
      pointX = this.physicsPoints[sideNumber].point.x;
      pointY = this.physicsPoints[sideNumber].point.y;
    }

    pt.set(pointX, pointY);
    return pt;
  },
  _updateConnectionMesh: function (params) {
    var mesh = params.mesh;
    var point = params.point;

    if (mesh) {
      mesh.position.x = point.x;
      mesh.position.y = point.y;
    }
  },
  rollover: function (isTransparent) {
    this.angularMatrix.rollover();
    for (var ii = 0; ii < this.physicsPoints.length; ii++) {if (window.CP.shouldStopExecution(5)) break;
      this.physicsPoints[ii].rollover();
    }window.CP.exitedLoop(5);

    if (isTransparent) com.gstar.TweenMax.to(this.material.uniforms.uOpacity, 0.6, { value: 0.4, ease: com.gstar.Quint.easeOut });
  },
  rollout: function () {
    com.gstar.TweenMax.to(this.material.uniforms.uOpacity, 0.6, { value: 1, ease: com.gstar.Quint.easeOut });
  },
  updateTexture: function (texture) {
    this.material.uniforms.texture.value = texture;
  },
  update: function (delta, mouseVelocity, scrollVelocity, rotationVelocity) {
    this.angularMatrix.update(delta, mouseVelocity, scrollVelocity, rotationVelocity);

    for (var ii = 0; ii < this.physicsPoints.length; ii++) {if (window.CP.shouldStopExecution(6)) break;
      this.physicsPoints[ii].updateOrigin(this.angularMatrix);
    }window.CP.exitedLoop(6);


    for (var ii = 0; ii < this.physicsPoints.length; ii++) {if (window.CP.shouldStopExecution(7)) break;
      this.physicsPoints[ii].update(delta);
      if (this.visible) this.positionAttribute.setXY(ii, this.physicsPoints[ii].point.x, this.physicsPoints[ii].point.y);
    }window.CP.exitedLoop(7);

    if (this._leftNumber) {
      this.leftConnectionPoint = this._calcalteConnectionPoint(this._leftNumber);
      this.leftConnectionGlobalPoint = this.leftConnectionPoint.clone();
      this.leftConnectionGlobalPoint.x += this.position.x;
      this.leftConnectionGlobalPoint.y += this.position.y;
      if (this._leftDebugMesh) this._updateConnectionMesh({ mesh: this._leftDebugMesh, point: this.leftConnectionPoint });
    }

    if (this._rightNumber) {
      this.rightConnectionPoint = this._calcalteConnectionPoint(this._rightNumber);
      this.rightConnectionGlobalPoint = this.leftConnectionPoint.clone();
      this.rightConnectionGlobalPoint.x += this.position.x;
      this.rightConnectionGlobalPoint.y += this.position.y;

      if (this._rightDebugMesh) this._updateConnectionMesh({ mesh: this._rightDebugMesh, point: this.rightConnectionPoint });
    }


    this.positionAttribute.needsUpdate = true;

  },
  debugCanvasDraw: function (debugCtx) {
    debugCtx.clearRect(0, 0, window.innerWidth, window.innerHeight);
    debugCtx.save();
    debugCtx.translate(window.innerWidth / 2, window.innerHeight / 2);
    this.angularMatrix.debugDraw(debugCtx);
    debugCtx.restore();
  },
  updateDebug: function (isDebug) {
    if (this._debugMesh) this._debugMesh.visible = isDebug;
  },
  animateIn: function (delay) {
    com.gstar.TweenMax.to(this.material.uniforms.uOpacity, 1.8, { value: 1, delay: delay, ease: com.gstar.Quint.easeInOut });
  },
  forceShow: function () {
    this.material.uniforms.uOpacity.value = 1.0;
  },
  findConnection: function (puppet) {
    if (puppet.leftConnectionPoint && this.rightConnectionPoint) {
      this._targetPoint = puppet.leftConnectionGlobalPoint.clone();

      this._targetPoint.x -= this.rightConnectionPoint.x + this._connectionMargin;
      this._targetPoint.y -= this.rightConnectionPoint.y;
    } else {
      this._targetPoint = null;
    }
  } });



/**
*   ========================
*         MagnetPuppet
*   ========================
*/

function MagnetPuppet(texture) {
  var conntectionLeft = 0;
  PuppetObject3D.call(this, {
    isDebug: false,
    connections: { left: { numArray: [9, 18], rate: 0.7 } },
    positionArray: magnetData.positionArray,
    uvArray: magnetData.uvArray,
    indexArray: magnetData.indexArray,
    neighborArray: magnetData.neighborArray,
    pivotPt: new THREE.Vector3(180, 0, 0),
    distanceType: 'x' });

  this.updateTexture(texture);
  this._width = texture.image.width;

  this._targetPosY = 0;
  this._prevPosY = 0;
  this._velocity = new THREE.Vector2();

  this.angularMatrix.updateCenter(0, 0);

  this.resize();
};

MagnetPuppet.prototype = Object.create(PuppetObject3D.prototype);
MagnetPuppet.prototype.constructor = MagnetPuppet;

_.extend(MagnetPuppet.prototype, {
  update: function () {
    this.position.y += (this._targetPosY - this.position.y) / 10;
    this._velocity.y = this.position.y - this._prevPosY;

    PuppetObject3D.prototype.update.call(this, 1 / 60, this._velocity, 0, 0, 0);

    this._prevPosY = this.position.y;
  },
  resize: function () {
    this.position.x = window.innerWidth / 2 - this._width / 2 + 80;
  },
  mousemove: function (posY) {
    this._targetPosY = posY;
  } });


/**
*   ========================
*         CoinPuppet
*   ========================
*/

function CoinPuppet(texture) {
  var conntectionLeft = 0;

  PuppetObject3D.call(this, {
    isDebug: false,
    connections: { left: 10, right: 14 },
    positionArray: coinData.positionArray,
    uvArray: coinData.uvArray,
    indexArray: coinData.indexArray,
    neighborArray: coinData.neighborArray,
    pivotPt: new THREE.Vector3(0, 0, 0) });

  this.updateTexture(texture);
  this._width = texture.image.width;
  this._height = texture.image.height;
  this._velocity = new THREE.Vector2();
  this.prevPosition = this.position.clone();
  this.direction = Math.random() < 0.5 ? -1 : 1;


  this.angularMatrix.updateCenter(0, 0);

  this.resize();
};

CoinPuppet.prototype = Object.create(PuppetObject3D.prototype);
CoinPuppet.prototype.constructor = CoinPuppet;

_.extend(CoinPuppet.prototype, {
  update: function () {

    if (this._targetPoint) {
      var distance = this._targetPoint.length();
      var k = 20; //Math.min(Math.max(distance/10, 8), 20);
      this.position.x += (this._targetPoint.x - this.position.x) / k;
      this.position.y += (this._targetPoint.y - this.position.y) / k;
    }
    this._velocity.x = this.position.x - this.prevPosition.x;
    this._velocity.y = this.position.y - this.prevPosition.y;
    this._velocity.multiplyScalar(0.1);

    PuppetObject3D.prototype.update.call(this, 1 / 60, this._velocity, 0, 0, 0);

    this.prevPosition = this.position.clone();
  },
  update2: function () {
    // this._velocity.x = this.position.x - this.prevPosition.x;
    this._velocity.y -= 0.4 * this.direction;
    this._velocity.multiplyScalar(0.99);

    this.position.x += this._velocity.x;
    this.position.y += this._velocity.y;
    this.scale.x *= 0.992;

    PuppetObject3D.prototype.update.call(this, 1 / 60, this._velocity, 0, 0, 0);

    if (this.position.y > window.innerHeight / 2 + this._height || this.position.y < -(window.innerHeight / 2 + this._height)) {
      this.dispatchEvent({ type: 'remove', coin: this });
    }
  },
  resize: function () {
    // this.position.x = window.innerWidth/2 - this._width/2 + 80;
  } });


/**
*   ========================
*             App
*   ========================
*/

class App {
  constructor(params) {
    this.params = params || {};
    this._removeUnnecessaryCoin = this._removeUnnecessaryCoin.bind(this);
    this.camera = new THREE.OrthographicCamera(-window.innerWidth / 2, window.innerWidth / 2, window.innerHeight / 2, -window.innerHeight / 2, 1, 10000);
    this.camera.position.z = 20;

    this._scene = new THREE.Scene();


    this.renderer = new THREE.WebGLRenderer({
      antialias: true });

    this.dom = this.renderer.domElement;

    if (this.params.isDebug) {
      this.stats = new Stats();
      document.body.appendChild(this.stats.dom);
      this._addGui();
    }

    this.clock = new THREE.Clock();
    this._targetPosY = 0;
    this._prevPosY = 0;
    this._mouseVelocity = new THREE.Vector2();


    this.resize();
  }

  _addGui() {
    this.gui = new dat.GUI();
  }

  createMesh() {
    let geo = new THREE.PlaneGeometry(1, 1);
    let mat = new THREE.RawShaderMaterial({
      vertexShader: glslify('../shaders/rawShader/shader.vert'),
      fragmentShader: glslify('../shaders/rawShader/shader.frag') });


    let mesh = new THREE.Mesh(geo, mat);
    return mesh;
  }

  _createMagnetMesh() {
    this._magnet = new MagnetPuppet(this._textures['magnet']);
    this._scene.add(this._magnet);
  }

  _createCoinMesh() {
    this._coins = [];

    var coin = new CoinPuppet(this._textures['coin']);
    this._scene.add(coin);
    this._coins.push(coin);
    coin.addEventListener('remove', this._removeUnnecessaryCoin);

    this._unnecessaryCoins = [];
  }
  _removeUnnecessaryCoin(event) {
    var index = -1;

    for (var ii = 0; ii < this._unnecessaryCoins.length; ii++) {if (window.CP.shouldStopExecution(8)) break;
      if (this._unnecessaryCoins[ii] === event.coin) {
        index = ii;
      }
    }window.CP.exitedLoop(8);

    if (index > -1) this._unnecessaryCoins.splice(index, 1);
  }

  animateIn(textures) {
    this._textures = textures;
    this._createMagnetMesh();
    this._createCoinMesh();
    TweenMax.ticker.addEventListener('tick', this.loop, this);
  }

  loop() {
    if (this._magnet) this._magnet.update(this._mouseVelocity);
    if (this._coins) {
      this._coins[0].findConnection(this._magnet);
      this._coins[0].update();

      for (var ii = 0; ii < this._coins.length - 1; ii++) {if (window.CP.shouldStopExecution(9)) break;
        this._coins[ii + 1].findConnection(this._coins[ii]);
        this._coins[ii + 1].update();
      }window.CP.exitedLoop(9);
    }

    if (this._unnecessaryCoins) {
      for (var ii = 0; ii < this._unnecessaryCoins.length; ii++) {if (window.CP.shouldStopExecution(10)) break;
        this._unnecessaryCoins[ii].update2();
      }window.CP.exitedLoop(10);
    }


    this.renderer.render(this._scene, this.camera);
    if (this.stats) this.stats.update();
  }

  animateOut() {
    TweenMax.ticker.removeEventListener('tick', this.loop, this);
  }

  onMouseMove(mouse) {
    if (this._magnet) this._magnet.mousemove(mouse.y * window.innerHeight / 2);
  }

  onKeyDown(ev) {
    switch (ev.which) {
      case 27:
        this.isLoop = !this.isLoop;
        if (this.isLoop) {
          this.clock.stop();
          TweenMax.ticker.addEventListener('tick', this.loop, this);
        } else {
          this.clock.start();
          TweenMax.ticker.removeEventListener('tick', this.loop, this);
        }
        break;}

  }

  resize() {
    this.camera.left = -window.innerWidth / 2;
    this.camera.right = window.innerWidth / 2;
    this.camera.top = window.innerHeight / 2;
    this.camera.bottom = -window.innerHeight / 2;
    this.camera.updateProjectionMatrix();

    if (this._magnet) this._magnet.resize();

    this.renderer.setSize(window.innerWidth, window.innerHeight);
  }

  destroy() {

  }

  incrementCoin() {

  var punValue = punArray[getRand(0, (punArray.length - 1))]
  $("#pun").html(punValue);

$("#pun").html( punArray[getRand(0, (punArray.length - 1))]);

    var coin = new CoinPuppet(this._textures['coin']);
    coin.addEventListener('remove', this._removeUnnecessaryCoin);
    this._scene.add(coin);
    this._coins.push(coin);

    coin.position.x = -window.innerWidth / 2 - THREE.Math.randFloat(200, 400);
    coin.position.y = THREE.Math.randFloat(-200, 200);

    if (this._coins.length > 8) {
      this._unnecessaryCoins.push(this._coins.shift());
    }


  }}




const imageSrcs = [
{ id: 'magnet', url: 'https://raw.githubusercontent.com/cibersergei/kanbas/master/cibersergei%20magnet.png' },
{ id: 'coin', url: 'https://raw.githubusercontent.com/cibersergei/kanbas/master/cibersergei%20coin%20vff.png' }];



var textures = [];

let app;
var loadedCnt = 0;

(() => {
  init();
  start();
})();

function init() {
  app = new App({
    isDebug: false });


  document.body.appendChild(app.dom);


}

function start() {
  // app.animateIn();
  (() => {
    imageSrcs.forEach(imgSrc => {
      var image = new Image();
      image.crossOrigin = 'anonymous';
      image.onload = () => {
        var texture = new THREE.Texture(image);
        texture.needsUpdate = true;
        texture.minFilter = THREE.LinearFilter;
        texture.maxFilter = THREE.LinearFilter;
        textures[imgSrc.id] = texture;
        loadedCnt++;
        if (loadedCnt === imageSrcs.length) onLoadedAssets();
      };
      image.src = imgSrc.url;
    });
  })();
}

function onLoadedAssets() {
  app.animateIn(textures);
  document.addEventListener('click', onDocumentClick, false);
  document.addEventListener('mousemove', onDocumentMouseMove, false);
}


function onDocumentMouseMove(event) {
  // event.preventDefault();

  let mouseX = event.clientX / window.innerWidth * 2 - 1;
  let mouseY = -(event.clientY / window.innerHeight) * 2 + 1;

  app.onMouseMove({ x: mouseX, y: mouseY });
}

function onDocumentClick() {
  app.incrementCoin();
}

window.addEventListener('resize', function () {
  app.resize();
});

window.addEventListener('keydown', function (ev) {
  app.onKeyDown(ev);
});



              
            
!
999px

Console