/**
* Roof Cleaning Drone Background Animations
* Creates animated drones with water spray effects
*/
(function() {
document.addEventListener('DOMContentLoaded', function() {
// Apply the background to the entire site
applyCleanBackground();
// Add animated drones to hero section
enhanceHeroSection();
// Add water droplet effects to service cards
enhanceServiceCards();
});
function applyCleanBackground() {
// Remove any existing star/cosmic backgrounds
const existingStars = document.querySelector('.stars');
if (existingStars) {
existingStars.remove();
}
// Add clean background to body
document.body.style.background = '#f8f9fa';
document.body.style.backgroundImage = `
linear-gradient(120deg, rgba(99, 183, 241, 0.1) 0%, transparent 40%),
linear-gradient(240deg, rgba(220, 237, 249, 0.2) 0%, transparent 40%)
`;
// Add subtle diagonal pattern
const pattern = document.createElement('div');
pattern.className = 'clean-pattern';
pattern.style.position = 'fixed';
pattern.style.top = '0';
pattern.style.left = '0';
pattern.style.width = '100%';
pattern.style.height = '100%';
pattern.style.pointerEvents = 'none';
pattern.style.opacity = '0.03';
pattern.style.zIndex = '-1';
pattern.style.backgroundImage = `
repeating-linear-gradient(
45deg,
#3498db,
#3498db 2px,
transparent 2px,
transparent 10px
)
`;
document.body.appendChild(pattern);
// Update text colors for better contrast on light background
document.querySelectorAll('p, h1, h2, h3, h4, h5, h6').forEach(el => {
// Only change if still using the dark theme colors
if (getComputedStyle(el).color === 'rgb(216, 216, 255)' ||
getComputedStyle(el).color === 'rgb(143, 143, 183)') {
el.style.color = '#505050';
}
});
}
function enhanceHeroSection() {
const heroSection = document.querySelector('.hero');
if (!heroSection) return;
// Remove any existing background
if (heroSection.style.backgroundImage.includes('stars-bg.jpg')) {
heroSection.style.backgroundImage = 'none';
}
// Create a sky gradient background
heroSection.style.background = 'linear-gradient(to bottom, #87CEEB 0%, #e6f7ff 100%)';
heroSection.style.position = 'relative';
heroSection.style.overflow = 'hidden';
// Create animation container
const animationContainer = document.createElement('div');
animationContainer.className = 'drone-animation-container';
animationContainer.style.position = 'absolute';
animationContainer.style.top = '0';
animationContainer.style.left = '0';
animationContainer.style.width = '100%';
animationContainer.style.height = '100%';
animationContainer.style.pointerEvents = 'none';
animationContainer.style.zIndex = '1';
heroSection.appendChild(animationContainer);
// Add roof silhouette
const roofSilhouette = document.createElement('div');
roofSilhouette.className = 'roof-silhouette';
roofSilhouette.style.position = 'absolute';
roofSilhouette.style.bottom = '0';
roofSilhouette.style.left = '0';
roofSilhouette.style.width = '100%';
roofSilhouette.style.height = '20%';
roofSilhouette.style.background = 'url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjAwIDIwMCI+PHBhdGggZD0iTTAgMjAwVjE1MEg1MEwxMDAgMTAwTDE1MCAxNTBIMjAwTDI1MCAxMDBMMzAwIDE1MEgzNTBMNDAwIDUwTDQ1MCAxNTBINTAwTDU1MCAxMDBMNjAwIDE1MEg2NTBMNzAwIDEwMEw3NTAgMTUwSDgwMEw4NTAgNTBMOTAwIDE1MEg5NTBMMTAwMCAxMDBMMTA1MCAxNTBIMTEwMEwxMTUwIDEwMEwxMjAwIDE1MFYyMDBIMFoiIGZpbGw9IiNlMGUwZTAiIGZpbGwtb3BhY2l0eT0iMC40Ii8+PC9zdmc+")';
roofSilhouette.style.backgroundSize = 'cover';
roofSilhouette.style.zIndex = '0';
animationContainer.appendChild(roofSilhouette);
// Create multiple drones with spray effects
createCleaningDrone(animationContainer, 20, 30, -1, 20);
createCleaningDrone(animationContainer, 60, 20, 1, 25);
createCleaningDrone(animationContainer, 40, 50, -1, 30);
// Add keyframes for animations
addDroneAnimationStyles();
}
function createCleaningDrone(container, startX, startY, direction, duration) {
// Create drone container
const droneElement = document.createElement('div');
droneElement.className = 'cleaning-drone';
droneElement.style.position = 'absolute';
droneElement.style.left = `${startX}%`;
droneElement.style.top = `${startY}%`;
droneElement.style.width = '60px';
droneElement.style.height = '60px';
droneElement.style.zIndex = '2';
// Calculate unique animation name
const animationName = `drone-path-${startX}-${startY}`;
droneElement.style.animation = `${animationName} ${duration}s linear infinite`;
// Create drone body
const droneBody = document.createElement('div');
droneBody.className = 'drone-body';
droneBody.style.position = 'relative';
droneBody.style.width = '40px';
droneBody.style.height = '40px';
droneBody.style.borderRadius = '50%';
droneBody.style.backgroundColor = '#3498db';
droneBody.style.border = '2px solid #2980b9';
droneBody.style.boxShadow = '0 2px 10px rgba(0, 0, 0, 0.2)';
droneBody.style.margin = '0 auto';
droneBody.style.zIndex = '2';
droneElement.appendChild(droneBody);
// Add central hub
const droneHub = document.createElement('div');
droneHub.className = 'drone-hub';
droneHub.style.position = 'absolute';
droneHub.style.top = '50%';
droneHub.style.left = '50%';
droneHub.style.width = '15px';
droneHub.style.height = '15px';
droneHub.style.borderRadius = '50%';
droneHub.style.backgroundColor = '#fff';
droneHub.style.transform = 'translate(-50%, -50%)';
droneHub.style.zIndex = '3';
droneBody.appendChild(droneHub);
// Add propellers
for (let i = 0; i < 4; i++) {
const propContainer = document.createElement('div');
propContainer.className = 'propeller-container';
propContainer.style.position = 'absolute';
propContainer.style.width = '15px';
propContainer.style.height = '15px';
// Position propellers around drone
switch(i) {
case 0: // top left
propContainer.style.top = '-10px';
propContainer.style.left = '-10px';
break;
case 1: // top right
propContainer.style.top = '-10px';
propContainer.style.right = '-10px';
break;
case 2: // bottom left
propContainer.style.bottom = '-10px';
propContainer.style.left = '-10px';
break;
case 3: // bottom right
propContainer.style.bottom = '-10px';
propContainer.style.right = '-10px';
break;
}
// Create propeller
const propeller = document.createElement('div');
propeller.className = 'propeller';
propeller.style.width = '100%';
propeller.style.height = '100%';
propeller.style.borderRadius = '50%';
propeller.style.borderTop = '2px solid rgba(255,255,255,0.8)';
propeller.style.borderLeft = '2px solid rgba(255,255,255,0.6)';
propeller.style.animation = 'spin-propeller 0.15s linear infinite';
propContainer.appendChild(propeller);
droneBody.appendChild(propContainer);
}
// Create water spray effect
const waterSpray = document.createElement('div');
waterSpray.className = 'water-spray';
waterSpray.style.position = 'absolute';
waterSpray.style.bottom = '-20px';
waterSpray.style.left = '50%';
waterSpray.style.transform = 'translateX(-50%)';
waterSpray.style.width = '30px';
waterSpray.style.height = '50px';
waterSpray.style.zIndex = '1';
droneElement.appendChild(waterSpray);
// Add water droplets to the spray
for (let i = 0; i < 12; i++) {
const droplet = document.createElement('div');
droplet.className = 'water-droplet';
droplet.style.position = 'absolute';
droplet.style.width = `${3 + Math.random() * 3}px`;
droplet.style.height = `${5 + Math.random() * 7}px`;
droplet.style.backgroundColor = 'rgba(173, 216, 230, 0.7)';
droplet.style.borderRadius = '50%';
// Randomize position within spray
const angle = Math.random() * 30 - 15; // -15 to 15 degrees
const distance = 5 + Math.random() * 45; // 5 to 50px
droplet.style.top = `${distance}px`;
droplet.style.left = '50%';
droplet.style.transform = `translateX(-50%) rotate(${angle}deg)`;
// Different animation duration for each droplet
const fallDuration = 0.5 + Math.random() * 0.5;
droplet.style.animation = `fall-droplet ${fallDuration}s infinite linear`;
waterSpray.appendChild(droplet);
}
// Create path animation for this specific drone
const keyframesStyle = document.createElement('style');
keyframesStyle.innerHTML = `
@keyframes ${animationName} {
0% {
transform: translateX(${direction > 0 ? '-100px' : '100vw'}) translateY(0px) rotate(${direction > 0 ? '0deg' : '180deg'});
}
25% {
transform: translateX(${direction > 0 ? 'calc(20vw)' : 'calc(80vw - 100px)'}) translateY(-20px) rotate(${direction > 0 ? '0deg' : '180deg'});
}
50% {
transform: translateX(${direction > 0 ? 'calc(40vw)' : 'calc(60vw - 100px)'}) translateY(30px) rotate(${direction > 0 ? '0deg' : '180deg'});
}
75% {
transform: translateX(${direction > 0 ? 'calc(60vw)' : 'calc(40vw - 100px)'}) translateY(-15px) rotate(${direction > 0 ? '0deg' : '180deg'});
}
100% {
transform: translateX(${direction > 0 ? '100vw' : '-100px'}) translateY(10px) rotate(${direction > 0 ? '0deg' : '180deg'});
}
}
`;
document.head.appendChild(keyframesStyle);
container.appendChild(droneElement);
}
function addDroneAnimationStyles() {
const styleSheet = document.createElement('style');
styleSheet.innerHTML = `
@keyframes spin-propeller {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@keyframes fall-droplet {
0% {
opacity: 0.8;
transform: translateX(-50%) translateY(0) scale(1);
}
100% {
opacity: 0;
transform: translateX(-50%) translateY(30px) scale(0.5);
}
}
`;
document.head.appendChild(styleSheet);
}
function enhanceServiceCards() {
const serviceCards = document.querySelectorAll('.service-card');
if (!serviceCards.length) return;
serviceCards.forEach(card => {
// Update card styling to match clean theme
card.style.backgroundColor = 'white';
card.style.borderRadius = '10px';
card.style.boxShadow = '0 10px 30px rgba(0, 0, 0, 0.1)';
card.style.border = '1px solid rgba(0, 0, 0, 0.05)';
card.style.overflow = 'hidden';
// Add water droplet accent at the top
const waterAccent = document.createElement('div');
waterAccent.className = 'water-accent';
waterAccent.style.height = '5px';
waterAccent.style.width = '100%';
waterAccent.style.position = 'absolute';
waterAccent.style.top = '0';
waterAccent.style.left = '0';
waterAccent.style.background = 'linear-gradient(90deg, #3498db, #00c2cb)';
card.prepend(waterAccent);
// Add subtle cleaning pattern to each card
addCleaningIconToCard(card);
});
}
function addCleaningIconToCard(card) {
// Create a container for the icon
const iconContainer = document.createElement('div');
iconContainer.className = 'cleaning-icon';
iconContainer.style.position = 'absolute';
iconContainer.style.top = '15px';
iconContainer.style.right = '15px';
iconContainer.style.width = '30px';
iconContainer.style.height = '30px';
iconContainer.style.opacity = '0.1';
// Randomly choose between different cleaning icons
const icons = [
// Water droplet
``,
// Spray bottle
``,
// Drone
``
];
// Choose a random icon
iconContainer.innerHTML = icons[Math.floor(Math.random() * icons.length)];
card.appendChild(iconContainer);
}
})();