diff --git a/index.html b/index.html index faa9166..6cb1060 100644 --- a/index.html +++ b/index.html @@ -2,7 +2,6 @@ - Instinct App - - -
+ + + - -
-

Instinct

- - +
+
+
+ +

RICARDO SANPRIETO
Creative Frontend developer

+ +
+
+ + +
+

Instinct

+ + +
+ +
+

Welcome,

+

Setup your account

+ + + +
+ +
+

Choose your avatar

+
+ Avatar 1 + Avatar 2 + Avatar 3 + Avatar 4
- - -
-

Welcome,

-

Setup your account

- - - + +
+ +
+
+
- - -
-

Choose your avatar

-
- Avatar 1 - Avatar 2 - Avatar 3 - Avatar 4 -
- +
+ +
- - -
-
- -
-
- - -
-
- -
+
+
- - + + } + + function validateEmail(email) { + const re = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + return re.test(String(email).toLowerCase()); + } + + function selectAvatar(avatarId) { + // Store the selected avatar or perform any action + console.log('Selected avatar:', avatarId); + } + + function bet(option) { + // Perform the betting action + console.log('Bet on:', option); + } + + document.addEventListener('DOMContentLoaded', () => { + startBallAnimation(); + preload(); + }); + + function startBallAnimation() { + const ball = document.createElement('div'); + ball.className = 'ball'; + document.body.appendChild(ball); + + let posX = Math.random() * (window.innerWidth - 100); + let posY = Math.random() * (window.innerHeight - 100); + let velX = (Math.random() * 20) - 10; // Increased speed + let velY = (Math.random() * 30) - 15; // Increased speed for higher bounce + const ballSize = 100; + const gravity = 0.5; // Increased gravity + const colors = Array.from({length: 40}, (_, i) => `hsl(${i * 9}, 100%, 50%)`); + let colorIndex = 0; + + function createFragment(x, y) { + const fragment = document.createElement('div'); + fragment.className = 'fragment'; + fragment.style.left = `${x}px`; + fragment.style.top = `${y}px`; + fragment.style.background = ball.style.background; + document.body.appendChild(fragment); + + const fragmentVelX = (Math.random() * 20) - 10; + const fragmentVelY = (Math.random() * 20) - 10; + const fragmentLife = Math.random() * 1000 + 500; // random lifespan between 500ms and 1500ms + + function moveFragment() { + x += fragmentVelX; + y += fragmentVelY; + fragment.style.transform = `translate(${x}px, ${y}px)`; + if (fragmentLife > 0) { + requestAnimationFrame(moveFragment); + } else { + fragment.remove(); + } + } + moveFragment(); + } + + function changeColor() { + colorIndex = (colorIndex + 1) % colors.length; + ball.style.background = colors[colorIndex]; + } + + function moveBall() { + posX += velX; + posY += velY; + velY += gravity; + + if (posX + ballSize > window.innerWidth) { + posX = window.innerWidth - ballSize; + velX *= -1; + changeColor(); + for (let i = 0; i < 5; i++) { + createFragment(posX + ballSize / 2, posY + ballSize / 2); + } + } else if (posX < 0) { + posX = 0; + velX *= -1; + changeColor(); + for (let i = 0; i < 5; i++) { + createFragment(posX + ballSize / 2, posY + ballSize / 2); + } + } + + if (posY + ballSize > window.innerHeight) { + posY = window.innerHeight - ballSize; + velY *= -1.1; // simulate bounce with increased height + changeColor(); + for (let i = 0; i < 5; i++) { + createFragment(posX + ballSize / 2, posY + ballSize / 2); + } + } else if (posY < 0) { + posY = 0; + velY *= -0.9; + changeColor(); + for (let i = 0; i < 5; i++) { + createFragment(posX + ballSize / 2, posY + ballSize / 2); + } + } + + ball.style.transform = `translate(${posX}px, ${posY}px)`; + requestAnimationFrame(moveBall); + } + + moveBall(); + } + + const preload = () => { + + let manager = new THREE.LoadingManager(); + manager.onLoad = function() { + const environment = new Environment( typo, particle ); + } + + var typo = null; + const loader = new THREE.FontLoader( manager ); + const font = loader.load('https://res.cloudinary.com/dydre7amr/raw/upload/v1612950355/font_zsd4dr.json', function ( font ) { typo = font; }); + const particle = new THREE.TextureLoader( manager ).load( 'https://res.cloudinary.com/dfvtkoboz/image/upload/v1605013866/particle_a64uzf.png'); + + } + + class Environment { + + constructor( font, particle ){ + + this.font = font; + this.particle = particle; + this.container = document.querySelector( '#magic' ); + this.scene = new THREE.Scene(); + this.createCamera(); + this.createRenderer(); + this.setup() + this.bindEvents(); + } + + bindEvents(){ + + window.addEventListener( 'resize', this.onWindowResize.bind( this )); + + } + + setup(){ + + this.createParticles = new CreateParticles( this.scene, this.font, this.particle, this.camera, this.renderer ); + } + + render() { + + this.createParticles.render() + this.renderer.render( this.scene, this.camera ) + } + + createCamera() { + + this.camera = new THREE.PerspectiveCamera( 65, this.container.clientWidth / this.container.clientHeight, 1, 10000 ); + this.camera.position.set( 0,0, 100 ); + + } + + createRenderer() { + + this.renderer = new THREE.WebGLRenderer(); + this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); + + this.renderer.setPixelRatio( Math.min( window.devicePixelRatio, 2)); + + this.renderer.outputEncoding = THREE.sRGBEncoding; + this.container.appendChild( this.renderer.domElement ); + + this.renderer.setAnimationLoop(() => { this.render() }) + + } + + onWindowResize(){ + + this.camera.aspect = this.container.clientWidth / this.container.clientHeight; + this.camera.updateProjectionMatrix(); + this.renderer.setSize( this.container.clientWidth, this.container.clientHeight ); + + } + } + + class CreateParticles { + + constructor( scene, font, particleImg, camera, renderer ) { + + this.scene = scene; + this.font = font; + this.particleImg = particleImg; + this.camera = camera; + this.renderer = renderer; + + this.raycaster = new THREE.Raycaster(); + this.mouse = new THREE.Vector2(-200, 200); + + this.colorChange = new THREE.Color(); + + this.buttom = false; + + this.data = { + + text: 'FUTURE\nIS NOW', + amount: 1500, + particleSize: 1, + particleColor: 0xffffff, + textSize: 16, + area: 250, + ease: .05, + } + + this.setup(); + this.bindEvents(); + + } + + + setup(){ + + const geometry = new THREE.PlaneGeometry( this.visibleWidthAtZDepth( 100, this.camera ), this.visibleHeightAtZDepth( 100, this.camera )); + const material = new THREE.MeshBasicMaterial( { color: 0x00ff00, transparent: true } ); + this.planeArea = new THREE.Mesh( geometry, material ); + this.planeArea.visible = false; + this.createText(); + + } + + bindEvents() { + + document.addEventListener( 'mousedown', this.onMouseDown.bind( this )); + document.addEventListener( 'mousemove', this.onMouseMove.bind( this )); + document.addEventListener( 'mouseup', this.onMouseUp.bind( this )); + + } + + onMouseDown(){ + + this.mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; + this.mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; + + const vector = new THREE.Vector3( this.mouse.x, this.mouse.y, 0.5); + vector.unproject( this.camera ); + const dir = vector.sub( this.camera.position ).normalize(); + const distance = - this.camera.position.z / dir.z; + this.currenPosition = this.camera.position.clone().add( dir.multiplyScalar( distance ) ); + + const pos = this.particles.geometry.attributes.position; + this.buttom = true; + this.data.ease = .01; + + } + + onMouseUp(){ + + this.buttom = false; + this.data.ease = .05; + } + + onMouseMove( ) { + + this.mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; + this.mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; + + } + + render( level ){ + + const time = ((.001 * performance.now())%12)/12; + const zigzagTime = (1 + (Math.sin( time * 2 * Math.PI )))/6; + + this.raycaster.setFromCamera( this.mouse, this.camera ); + + const intersects = this.raycaster.intersectObject( this.planeArea ); + + if ( intersects.length > 0 ) { + + const pos = this.particles.geometry.attributes.position; + const copy = this.geometryCopy.attributes.position; + const coulors = this.particles.geometry.attributes.customColor; + const size = this.particles.geometry.attributes.size; + + const mx = intersects[ 0 ].point.x; + const my = intersects[ 0 ].point.y; + const mz = intersects[ 0 ].point.z; + + for ( var i = 0, l = pos.count; i < l; i++) { + + const initX = copy.getX(i); + const initY = copy.getY(i); + const initZ = copy.getZ(i); + + let px = pos.getX(i); + let py = pos.getY(i); + let pz = pos.getZ(i); + + this.colorChange.setHSL( .5, 1 , 1 ) + coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b ) + coulors.needsUpdate = true; + + size.array[ i ] = this.data.particleSize; + size.needsUpdate = true; + + let dx = mx - px; + let dy = my - py; + const dz = mz - pz; + + const mouseDistance = this.distance( mx, my, px, py ) + let d = ( dx = mx - px ) * dx + ( dy = my - py ) * dy; + const f = - this.data.area/d; + + if( this.buttom ){ + + const t = Math.atan2( dy, dx ); + px -= f * Math.cos( t ); + py -= f * Math.sin( t ); + + this.colorChange.setHSL( .5 + zigzagTime, 1.0 , .5 ) + coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b ) + coulors.needsUpdate = true; + + if ((px > (initX + 70)) || ( px < (initX - 70)) || (py > (initY + 70) || ( py < (initY - 70)))){ + + this.colorChange.setHSL( .15, 1.0 , .5 ) + coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b ) + coulors.needsUpdate = true; + + } + + }else{ + + if( mouseDistance < this.data.area ){ + + if(i%5==0){ + + const t = Math.atan2( dy, dx ); + px -= .03 * Math.cos( t ); + py -= .03 * Math.sin( t ); + + this.colorChange.setHSL( .15 , 1.0 , .5 ) + coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b ) + coulors.needsUpdate = true; + + size.array[ i ] = this.data.particleSize /1.2; + size.needsUpdate = true; + + }else{ + + const t = Math.atan2( dy, dx ); + px += f * Math.cos( t ); + py += f * Math.sin( t ); + + pos.setXYZ( i, px, py, pz ); + pos.needsUpdate = true; + + size.array[ i ] = this.data.particleSize * 1.3 ; + size.needsUpdate = true; + } + + if ((px > (initX + 10)) || ( px < (initX - 10)) || (py > (initY + 10) || ( py < (initY - 10)))){ + + this.colorChange.setHSL( .15, 1.0 , .5 ) + coulors.setXYZ( i, this.colorChange.r, this.colorChange.g, this.colorChange.b ) + coulors.needsUpdate = true; + + size.array[ i ] = this.data.particleSize /1.8; + size.needsUpdate = true; + + } + } + + } + + px += ( initX - px ) * this.data.ease; + py += ( initY - py ) * this.data.ease; + pz += ( initZ - pz ) * this.data.ease; + + pos.setXYZ( i, px, py, pz ); + pos.needsUpdate = true; + + } + } + } + + createText(){ + + let thePoints = []; + + let shapes = this.font.generateShapes( this.data.text , this.data.textSize ); + let geometry = new THREE.ShapeGeometry( shapes ); + geometry.computeBoundingBox(); + + const xMid = - 0.5 * ( geometry.boundingBox.max.x - geometry.boundingBox.min.x ); + const yMid = (geometry.boundingBox.max.y - geometry.boundingBox.min.y)/2.85; + + geometry.center(); + + let holeShapes = []; + + for ( let q = 0; q < shapes.length; q ++ ) { + + let shape = shapes[ q ]; + + if ( shape.holes && shape.holes.length > 0 ) { + + for ( let j = 0; j < shape.holes.length; j ++ ) { + + let hole = shape.holes[ j ]; + holeShapes.push( hole ); + } + } + + } + shapes.push.apply( shapes, holeShapes ); + + let colors = []; + let sizes = []; + + for ( let x = 0; x < shapes.length; x ++ ) { + + let shape = shapes[ x ]; + + const amountPoints = ( shape.type == 'Path') ? this.data.amount/2 : this.data.amount; + + let points = shape.getSpacedPoints( amountPoints ) ; + + points.forEach( ( element, z ) => { + + const a = new THREE.Vector3( element.x, element.y, 0 ); + thePoints.push( a ); + colors.push( this.colorChange.r, this.colorChange.g, this.colorChange.b); + sizes.push( 1 ) + + }); + } + + let geoParticles = new THREE.BufferGeometry().setFromPoints( thePoints ); + geoParticles.translate( xMid, yMid, 0 ); + + geoParticles.setAttribute( 'customColor', new THREE.Float32BufferAttribute( colors, 3 ) ); + geoParticles.setAttribute( 'size', new THREE.Float32BufferAttribute( sizes, 1) ); + + const material = new THREE.ShaderMaterial( { + + uniforms: { + color: { value: new THREE.Color( 0xffffff ) }, + pointTexture: { value: this.particleImg } + }, + vertexShader: document.getElementById( 'vertexshader' ).textContent, + fragmentShader: document.getElementById( 'fragmentshader' ).textContent, + + blending: THREE.AdditiveBlending, + depthTest: false, + transparent: true, + } ); + + this.particles = new THREE.Points( geoParticles, material ); + this.scene.add( this.particles ); + + this.geometryCopy = new THREE.BufferGeometry(); + this.geometryCopy.copy( this.particles.geometry ); + + } + + visibleHeightAtZDepth ( depth, camera ) { + + const cameraOffset = camera.position.z; + if ( depth < cameraOffset ) depth -= cameraOffset; + else depth += cameraOffset; + + const vFOV = camera.fov * Math.PI / 180; + + return 2 * Math.tan( vFOV / 2 ) * Math.abs( depth ); + } + + visibleWidthAtZDepth( depth, camera ) { + + const height = this.visibleHeightAtZDepth( depth, camera ); + return height * camera.aspect; + + } + + distance (x1, y1, x2, y2){ + + return Math.sqrt(Math.pow((x1 - x2), 2) + Math.pow((y1 - y2), 2)); + } + } +