Home   |    Blog
Create an Interactive CCTV Animation That Tracks Mouse Movement
January 2, 2025
Let Us Help You, Make The Right Choice!

Adding interactive elements to your website can significantly enhance user engagement. A CCTV animation, which follows the user’s mouse movement, is an excellent addition for businesses like security firms and CCTV providers. This interactive feature symbolizes vigilance and security while providing a visually engaging experience.

In this guide, we’ll explore how to create this animation using HTML, CSS, and JavaScript with Three.js and GSAP libraries. The result will be a realistic 3D CCTV camera that smoothly follows the cursor.

Why Add an Interactive CCTV Animation?

Interactive animations are more than just eye candy; they can convey messages and themes effectively. Here’s why this CCTV animation could benefit your website:

  • Symbolism: Ideal for security firms, it represents surveillance and vigilance.
  • Engagement: Encourages users to explore the site, as the camera “watches” them move.
  • Modern Aesthetic: A cutting-edge 3D animation aligns your brand with innovation.
  • Personalization: Adds a touch of interactivity that resonates with visitors.

Live Demo

Experience the CCTV animation in action: CodePen URL
View the CCTV Animation Demo

This animation adapts to the user’s movements and can be customized to fit your brand or theme.

Tools and Libraries Used

To build this animation, we’ll use the following tools:

  • HTML5: Provides the structure for the canvas and other elements.
  • CSS3: Styles the canvas and background to ensure a seamless user experience.
  • Three.js: A JavaScript library for creating 3D graphics in the browser.
  • GSAP (TweenMax): A robust library for animations, ensuring smooth transitions.

Step-by-Step Guide

Step 1: HTML Structure

The HTML is straightforward, containing a canvas element for rendering the animation.

<div id="wrapper">
    <canvas id="canvas3d"></canvas>
    <div id="bg"></div>
</div>
  • #wrapper: Acts as a container for the animation and background.
  • #canvas3d: The main canvas for rendering the 3D CCTV model.
  • #bg: A simple background layer to enhance the visual depth.

Step 2: CSS Styling

The CSS ensures the canvas fills the screen and provides a sleek black background.

html, body {
	margin: 0;
	padding: 0;
}

#wrapper {
	position: absolute;
	width: 100%;
	height: 100%;
	overflow: hidden;
}

canvas {
	position: absolute;
	top: 0;
	left: 0;
}

#intro {
  background-color: #000;
}

#bg {
  position: absolute;
  width: 100%;
  height: 100%;
  background-color: #000;
}

#canvas3d
{
  background-color: #000;
}

Step 3: JavaScript Logic

The JavaScript drives the 3D rendering and interactivity. It involves:

  1. Initializing the Scene
    Set up the Three.js scene, camera, and renderer.
(function(window) {
	
	function Fly(camera, onReady) {
    this.onReady = onReady;
		this.mouseX = 0;
		this.mouseY = 0;
		this.camera = camera;
    
		this.el = new THREE.Group();
		this.el.position.z = 10;
		Utils.loadOBJ('https://s3-us-west-2.amazonaws.com/s.cdpn.io/356608/butterfly.obj', null, function(object) {
			object.traverse(function(child) {
				if (child.type === 'Mesh') {
          child.material = new THREE.MeshPhongMaterial({color: 0xd45f00, side: THREE.DoubleSide});
				}
			});
			
			this.body = object;
			this.body.scale.set(4, 4, 4)
			this.el.add(this.body);
			
			var wingLeft = this.el.getObjectByName('Wing_Left');
			var wingRight = this.el.getObjectByName('Wing_Right');
			
			// Animation
			TweenMax.to(this.body.position, 0.5, {y: 0.5, yoyo: true, repeat: -1, ease: Quad.easeInOut});
			TweenMax.to(wingLeft.rotation, 0.1, {z: Utils.toRad(-85), repeat: -1, yoyo: true, ease: Linear.easeNone});
			TweenMax.to(wingRight.rotation, 0.1, {z: Utils.toRad(85), repeat: -1, yoyo: true, ease: Linear.easeNone});
      
      this.onReady();
		}.bind(this));
		
		document.addEventListener('mousemove', this.onMouseMove.bind(this));
	}
	
	Fly.prototype.onMouseMove = function(e) {
		this.mouseX = e.clientX;
		this.mouseY = e.clientY;
		this.moveTo(this.mouseX, this.mouseY);
	}
	
	Fly.prototype.moveTo = function(x, y) {
		var vec3 = Utils.unproject2DCoords(x, y, this.camera, this.el.position.z);
		TweenLite.to(this.el.position, 0.3, {x: vec3.x, y: vec3.y, ease: Linear.easeNone});
	}
	
	window.Fly = Fly;
	
})(window);


(function(window) {
  
	function Watcher(camera, onReady) {
    this.onReady = onReady;
		this.camera = camera;
		this.mouseX = 0;
		this.mouseY = 0;
		this.walkerY = 0;
		this.walkerX = 0;
		this.loaded = false;
		
		var self = this;
		
		this.el = new THREE.Object3D();
		var scale = 1.7;
		this.el.scale.set(scale, scale, scale);
		
		setTimeout(function() {
			var vec3 = Utils.unproject2DCoords(window.innerWidth / 3, window.innerHeight / 2, camera, 5);
			this.el.position.set(vec3.x, vec3.y, 5);
		}.bind(this), 0)

		
		// Load OBJ File with Materials
		Utils.loadOBJ('https://s3-us-west-2.amazonaws.com/s.cdpn.io/356608/cam.obj', 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/356608/cam.mtl', function(object) {
			var body = new THREE.Object3D(),
					base = new THREE.Object3D(),
					pivot = new THREE.Object3D();
			
			// Apply shadows
			object.traverse( function(child) {
				if ( child instanceof THREE.Mesh ) {
	        child.castShadow = true;
	        child.receiveShadow = true;
		    }
			})
			
      var glass = object.getObjectByName('Glass');
      glass.material = new THREE.MeshPhongMaterial({color: 'black', shininess: 300, reflectivity: 10, opacity: 0.7});
      glass.material.transparent = true;
      
       var cam_body = object.getObjectByName('cam_body');
      cam_body.material = new THREE.MeshPhongMaterial({color: 'gray', shininess: 300, reflectivity: 10, opacity: 1});
      
      var cam_body = object.getObjectByName('cam_base');
      cam_body.material = new THREE.MeshPhongMaterial({color: 'gray', shininess: 300, reflectivity: 10, opacity: 1});
      
            var cam_body = object.getObjectByName('rain_cover');
      cam_body.material = new THREE.MeshPhongMaterial({color: 'gray', shininess: 300, reflectivity: 10, opacity: 1});
      
      var cam_body = object.getObjectByName('Rotate_node_Z');
      cam_body.material = new THREE.MeshPhongMaterial({color: 'gray', shininess: 300, reflectivity: 10, opacity: 1});
      
      var cam_body = object.getObjectByName('rotate_node02');
      cam_body.material = new THREE.MeshPhongMaterial({color: 'gray', shininess: 300, reflectivity: 10, opacity: 1});
     
      
			// Separate parts of the camera into groups
			body.add(object.getObjectByName('lens_body'));
      body.add(object.getObjectByName('Glass'));
			body.add(object.getObjectByName('cam_body'));
			body.add(object.getObjectByName('rotate_node02'));
			body.add(object.getObjectByName('lens01'));
			body.add(object.getObjectByName('rain_cover'));
			base.add(object.getObjectByName('cam_base'));
			pivot.add(object.getObjectByName('Rotate_node_Z'));
			
			self.body = body;
			self.base = base;
			self.pivot = pivot;
			
			self.el.add(body);
			self.el.add(base);
			self.el.add(pivot);
			
			self.loaded = true;
			self.onReady();
		});
		
		document.addEventListener('mousemove', this.onMouseMove.bind(this));
	}
  
  Watcher.prototype.onMouseMove = function(e) {
    this.mouseX = e.clientX;
		this.mouseY = e.clientY;
  
    var vec3 = Utils.unproject2DCoords(this.mouseX, this.mouseY, this.camera, 10).sub(new THREE.Vector3(this.el.position.x - 2, this.el.position.y + 2, 0));
		TweenMax.rotateTo(this.body, 0.1, {vector: vec3, ease: Linear.easeNone, delay: 0.2});
  }

	window.Watcher = Watcher;
})(window);


var wW,
		wH,
		canvas3d,
		canvas2d,
		scene,
		camera,
		renderer,
		watcher,
		lights = [],
		plane,
		fly,
    numObjectsLoaded = 0;
		
function init() {
	canvas3d = document.getElementById('canvas3d');
	setSize();
  $('#intro').css('opacity', '1');
  
	// Set up 3D Canvas
	scene = new THREE.Scene();
	camera = new THREE.PerspectiveCamera(40, wW / wH, 0.1, 1000);
	camera.position.z = 28;
	camera.lookAt(scene.position);
	renderer = new THREE.WebGLRenderer({
    canvas: canvas3d,
    antialias: true,
    alpha: true
  });
	renderer.setSize(wW, wH);
	renderer.shadowMap.enabled = true;
	
  watcher = new Watcher(camera, checkReady);
	scene.add(watcher.el);
  
	var light = new THREE.SpotLight(0xffffff);
	var vec3 = Utils.unproject2DCoords(window.innerWidth / 5, window.innerHeight / 5, camera, 3);
	light.position.set(vec3.x + 8, vec3.y + 24, 25);
//	light.castShadow = true;
//	light.shadow.mapSize.width = 4096;
	//light.shadow.mapSize.height = 4096;
//	light.shadow.camera.near = 1;
//	light.shadow.camera.far = 200;
//	light.shadow.camera.fov = 45;
	scene.add(light);
	
	var light2 = new THREE.AmbientLight(0xffffff, 0.05);
//	scene.add(light2);
	fly = new Fly(camera, checkReady);
	

	
	light.lookAt(watcher.el.position);
	
	render();
}

function setSize() {
	wW = window.innerWidth;
	wH = window.innerHeight;

  $('#intro').css({
    left: (wW / 2) - ($('#intro').width() / 2),
    top: (wH / 2) - ($('#intro').height() / 2)
  })
  
	canvas3d.style.width = wW + 'px';
  canvas3d.style.height = wH + 'px';
}

function checkReady() {
  numObjectsLoaded++;
  console.log(numObjectsLoaded)
  if (numObjectsLoaded >= 2) {
    TweenLite.to('#intro, #bg', 1, {opacity: 0});
  }
}

function render() {
	requestAnimationFrame(render);
	renderer.render(scene, camera);
}

$(document).ready(init);
  • Loading the CCTV Model
    Use Utils.loadOBJ() to load the CCTV model and apply materials to different parts.
  • Handling Mouse Movement
    Track the mouse’s position and calculate the corresponding 3D coordinates using Utils.unproject2DCoords().
  • Animating the Camera
    Use GSAP’s TweenLite for smooth transitions as the CCTV camera follows the cursor.

Implementation Tips

  1. File Hosting: Ensure the 3D model files (cam.obj and cam.mtl) are hosted on a reliable server. You can use a CDN or your own server for this purpose.
  2. Performance Optimization:
    • Use compressed 3D models to reduce load times.
    • Limit animations to ensure smooth performance on lower-end devices.
  3. Mobile Compatibility: While this animation works best on desktops, you can add fallback visuals for mobile users.

Customization Ideas

Make the animation truly yours by customizing the following:

  • Camera Colors: Match the colors to your brand’s theme.
  • Background Effects: Add gradients or textures to the background.
  • Animation Speed: Adjust the transition duration for a faster or slower response.
  • Additional Elements: Integrate the animation with your site’s navigation or other interactive features.

Use Cases

While the CCTV animation is perfect for security-related websites, its application can extend to other industries:

  • Gaming Websites: A surveillance theme to enhance immersive storytelling.
  • Tech Blogs: Showcase innovation and creativity with interactive visuals.
  • Portfolio Sites: Highlight design and development skills with a unique touch.

Interactive animations like this CCTV tracker not only enhance aesthetics but also convey your message effectively. By following this guide, you can add a touch of interactivity and innovation to your website. Try it today and elevate your web presence!

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *

×

Hello!

Click one of our agent below to chat on WhatsApp

× How can I help you?