This is my canvas code, it’s just a simple circle animation with some mousemove effect, but when i try to change my resolution it will make it bigger and messy. Also not working on mobile. IT usually hapens when we scroll down a bit fast, I have added an image you can check dowm below. here’s my code.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Document</title>
</head>
<body>
<div id="main">
<div class="hp-hands-wrapper" data-scroll-section="" style="z-index: initial; transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); opacity: 1; pointer-events: all;" data-scroll-section-inview="">
<div class="object3d-anchor is-inview" data-scroll="" data-scroll-repeat="" data-scroll-call="3dObject" data-scroll-offset="20%"></div>
<div class="bg-circle">
<div class="mobile-circle-wrapper">
<div class="inner">
<div class="mobile-pink-circle"></div>
<div class="mobile-circle mc-01"></div>
<div class="mobile-circle mc-02"></div>
</div>
</div>
</div>
<h1 class="hands-hdl show is-inview" data-scroll-speed="2" data-scroll="" style="transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1.2, 0, 1);">
<span id="trigger" class="hands-hdl-01 hands-hdl thinkers txt show">predicting the</span> <br>
<span class="hands-hdl-03 hands-hdl doers txt show">next trend</span>
</h1>
<canvas class="scene show is-inview" id="bubble" data-scroll="" width="1920" height="919" style="width: 1920px; height: 919px;"></canvas>
<h3 class="hands-subhdl el-fade-in is-inview" data-scroll="" data-scroll-speed="1.5" style="transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 14.475, 0, 1);">
with 10 years of experience we already know what today’s trends mean for tomorrow’s world. </h3>
<a href="#" class="btn-scroll-down mlink"></a>
<div class="el-plax el-plax--00 is-inview" data-scroll="" data-scroll-speed="4" style="transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 23.35, 0, 1);"></div>
</div>
</div>
<!-- three.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/97/three.min.js"></script>
<script src="https://cdn.rawgit.com/josephg/noisejs/master/perlin.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.2/TweenMax.min.js"></script>
<script>
/*--------------------
Setup
--------------------*/
let isMobile = window.matchMedia("only screen and (max-width: 649px)").matches;
let isTablet = window.matchMedia("only screen and (min-width: 650px) and (max-width: 990px)").matches;
let isTabletProAndDesktop = window.matchMedia("only screen and (min-width: 830px)").matches;
let isDesktop = window.matchMedia("only screen and (min-width: 1113px)").matches;
let isTouchDevice = window.matchMedia("only screen and (hover: none) and (pointer: coarse)").matches;
console.clear();
const canvas = document.querySelector('#bubble');
let pixelRatio = window.devicePixelRatio
let AA = true
if (pixelRatio > 1) {
AA = false
}
let width = canvas.offsetWidth,
height = canvas.offsetHeight;
const renderer = new THREE.WebGLRenderer({
canvas: canvas,
antialias: AA,
powerPreference: "high-performance",
alpha: true
});
const scene = new THREE.Scene();
const setup = () => {
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
renderer.setClearColor(0xebebeb, 0);
renderer.shadowMap.enabled = true;
renderer.shadowMapSoft = true;
// scene.fog = new THREE.Fog(0x4814B8, 20, 950);
const aspectRatio = width / height;
const fieldOfView = 100;
const nearPlane = 0.1;
const farPlane = 10000;
camera = new THREE.PerspectiveCamera(
fieldOfView,
aspectRatio,
nearPlane,
farPlane
);
camera.position.x = 0;
if(isMobile){
camera.position.y = -60;
}else{
camera.position.y = -10;
}
// camera.position.y = -100;
camera.position.z = 270;
}
setup();
/*--------------------
Lights
--------------------*/
let hemispshereLight, shadowLight, light2;
const createLights = () => {
hemisphereLight = new THREE.HemisphereLight(0xFCDCEF, 0x4A7DFF, .3),
shadowLight = new THREE.DirectionalLight(0xE4C8FF, .1);
shadowLight.position.set(0, 1650, 450);
shadowLight.castShadow = true;
shadowLight.shadow.radius = 18;
shadowLight.shadow.camera.left = -950;
shadowLight.shadow.camera.right = 950;
shadowLight.shadow.camera.top = 950;
shadowLight.shadow.camera.bottom = -950;
shadowLight.shadow.camera.near = 1;
shadowLight.shadow.camera.far = 4000;
shadowLight.shadow.mapSize.width = 4096;
shadowLight.shadow.mapSize.height = 4096;
light2 = new THREE.DirectionalLight(0xFBD44B, .25);
light2.position.set(-600, 350, 350);
light3 = new THREE.DirectionalLight(0x8EBBFF, .45);
light3.position.set(0, -250, 300);
scene.add(hemisphereLight);
scene.add(shadowLight);
scene.add(light2);
scene.add(light3);
}
createLights();
initGui();
/*--------------------
Bubble
--------------------*/
const vertex = width > 575 ? 80 : 40;
const bubbleGeometry = new THREE.SphereGeometry(120, vertex, vertex);
let bubble, bubbleMaterial;
const createBubble = () => {
for (let i = 0; i < bubbleGeometry.vertices.length; i++) {
let vector = bubbleGeometry.vertices[i];
vector.original = vector.clone();
}
bubbleMaterial = new THREE.MeshStandardMaterial({
emissive: 0xAA8CFF, //change color code here
emissiveIntensity: 0.7,
roughness: 0.8,
metalness: 0.5,
side: THREE.FrontSide
});
bubble = new THREE.Mesh(bubbleGeometry, bubbleMaterial);
bubble.castShadow = true;
bubble.receiveShadow = false;
scene.add(bubble);
}
createBubble();
/*--------------------
Plane
--------------------*/
const createPlane = () => {
// const planeGeometry = new THREE.PlaneBufferGeometry(2000, 2000);
const planeGeometry = new THREE.PlaneBufferGeometry(2500, 2500);
const planeMaterial = new THREE.ShadowMaterial({
opacity: 0.1
});
const plane = new THREE.Mesh(planeGeometry, planeMaterial);
plane.position.y = -200;
plane.position.x = 0;
plane.position.z = 0;
plane.rotation.x = Math.PI / 180 * -90;
plane.receiveShadow = true;
scene.add(plane);
}
createPlane();
/*--------------------
Map
--------------------*/
const map = (num, in_min, in_max, out_min, out_max) => {
return (num - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
/*--------------------
Distance
--------------------*/
const distance = (a, b) => {
const dx = a.x - b.x;
const dy = a.y - b.y;
const d = Math.sqrt(dx * dx + dy * dy);
return d;
}
/*--------------------
Mouse
--------------------*/
let mouse = new THREE.Vector2(0, 0);
const onMouseMove = (e) => {
TweenMax.to(mouse, 0.8, {
x: e.clientX || e.pageX || e.touches[0].pageX || 0,
y: e.clientY || e.pageY || e.touches[0].pageY || 0,
ease: Power2.easeOut
});
};
if(!isTouchDevice){
['mousemove', 'touchmove'].forEach(event => {
window.addEventListener(event, onMouseMove);
});
}
/*--------------------
Spring
--------------------*/
let spring = {
scale: 1
};
const clicking = {
down: () => {
TweenMax.to(spring, 1.1, {
scale: 1.0,
ease: Power3.easeOut
});
},
up: () => {
TweenMax.to(spring, .9, {
scale: 1,
ease: Elastic.easeOut
});
}
};
if(!isTouchDevice){
['mousedown', 'touchstart'].forEach(event => {
window.addEventListener(event, clicking.down);
});
['mouseup', 'touchend'].forEach(event => {
window.addEventListener(event, clicking.up);
});
}
/*--------------------
Resize
--------------------*/
const onResize = () => {
canvas.style.width = '';
canvas.style.height = '';
width = canvas.offsetWidth;
height = canvas.offsetHeight;
camera.aspect = width / height;
camera.updateProjectionMatrix();
maxDist = distance(mouse, {
x: width / 2,
y: height / 2
});
renderer.setSize(width, height);
}
let resizeTm;
window.addEventListener('resize', function () {
resizeTm = clearTimeout(resizeTm);
resizeTm = setTimeout(onResize, 200);
});
/*--------------------
Noise
--------------------*/
let dist = new THREE.Vector2(0, 0);
let maxDist = distance(mouse, {
x: width / 2,
y: height / 2
});
const updateVertices = (time) => {
dist = distance(mouse, {
x: width / 2,
y: height / 2
});
dist /= maxDist;
dist = map(dist, 1, 0, 0, 1);
for (let i = 0; i < bubbleGeometry.vertices.length; i++) {
let vector = bubbleGeometry.vertices[i];
vector.copy(vector.original);
let perlin = noise.simplex3(
(vector.x * 0.005) + (time * 0.0005), // Adjust the time multiplier for faster animation
(vector.y * 0.005) + (time * 0.0005), // Adjust the time multiplier for faster animation
(vector.z * 0.005)
);
let ratio = ((perlin * 0.35 * (dist + 0.3)) + 0.8); //scale the animation
vector.multiplyScalar(ratio);
}
bubbleGeometry.verticesNeedUpdate = true;
}
function initGui() {
const trigger = document.getElementById('trigger');
trigger.addEventListener('mouseenter', e => {
changeColors();
});
trigger.addEventListener('mouseleave', e => {
revertColors();
});
}
function revertColors() {
light2.color.setHex(0xAA8CFF); // Change color here
bubbleMaterial.emissive.setHex(0xAA8CFF); // Change color here
conf.light1Color = chroma.random().hex();
conf.light2Color = chroma.random().hex();
conf.light3Color = chroma.random().hex();
light1.color = new THREE.Color(conf.light1Color);
light2.color = new THREE.Color(conf.light2Color);
light3.color = new THREE.Color(conf.light3Color);
console.log(conf);
}
function changeColors() {
light2.color.setHex(0xAA8CFF); // Change color here
bubbleMaterial.emissive.setHex(0xAA8CFF); // Change color here
conf.light1Color = chroma.random().hex();
conf.light2Color = chroma.random().hex();
conf.light3Color = chroma.random().hex();
light1.color = new THREE.Color(conf.light1Color);
light2.color = new THREE.Color(conf.light2Color);
light3.color = new THREE.Color(conf.light3Color);
console.log(conf);
}
/*--------------------
Animate
--------------------*/
var stopRender = false;
const render = (a) => {
if(stopRender){
return true;
}
requestAnimationFrame(render);
bubble.rotation.y = -4 + map(mouse.x, 0, width, 0, 4);
bubble.rotation.z = 4 + map(mouse.y, 0, height, 0, -4);
// bubble.rotation.y = -4 + map(mouse.x, 0, width, 0, 4);
// bubble.rotation.z = 4 + map(mouse.y, 0, height, 0, -4);
bubble.scale.set(spring.scale, spring.scale, spring.scale);
updateVertices(a);
renderer.clear();
renderer.render(scene, camera);
}
function frameThrottle(original) {
let pending = false;
function wrap() {
pending = false;
original();
}
function proxy() {
if (!pending) {
pending = true;
requestAnimationFrame(wrap);
}
}
return proxy;
}
if(isTabletProAndDesktop){
frameThrottle(requestAnimationFrame(render));
renderer.render(scene, camera);
}
if(isTabletProAndDesktop){
function stopRendering(){
stopRender = true;
}
function resumeRendering(){
stopRender = false;
requestAnimationFrame(render);
}
}
</script>
</body>
</html>
I have tried couple of things like resizing, time reduce, but it does’nt work for me.