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:
- 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
UseUtils.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 usingUtils.unproject2DCoords()
. - Animating the Camera
Use GSAP’sTweenLite
for smooth transitions as the CCTV camera follows the cursor.
Implementation Tips
- File Hosting: Ensure the 3D model files (
cam.obj
andcam.mtl
) are hosted on a reliable server. You can use a CDN or your own server for this purpose. - Performance Optimization:
- Use compressed 3D models to reduce load times.
- Limit animations to ensure smooth performance on lower-end devices.
- 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