Please bookmark this page to avoid losing your image tool!

Image Alarm Clock Tool

(Free & Supports Bulk Upload)

Drag & drop your images here or

The result will appear here...
You can edit the below JavaScript code to customize the image tool.
function processImage(originalImg, presetAlarmTime = "07:00", clockFormat = "digital") {
    // Create the main container
    const container = document.createElement('div');
    container.style.position = 'relative';
    container.style.display = 'inline-block';
    container.style.fontFamily = '"Segoe UI", Tahoma, Geneva, Verdana, sans-serif';
    container.style.boxShadow = '0 4px 8px rgba(0,0,0,0.3)';
    container.style.borderRadius = '10px';
    container.style.overflow = 'hidden';

    // Create the canvas for drawing the image and clock
    const canvas = document.createElement('canvas');
    const canvasWidth = originalImg.width;
    const canvasHeight = originalImg.height;
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;
    canvas.style.display = 'block';
    canvas.style.maxWidth = '100%';
    canvas.style.height = 'auto';
    container.appendChild(canvas);

    const ctx = canvas.getContext('2d');

    // Create the UI overlay
    const uiContainer = document.createElement('div');
    uiContainer.style.position = 'absolute';
    uiContainer.style.bottom = '5%';
    uiContainer.style.left = '50%';
    uiContainer.style.transform = 'translateX(-50%)';
    uiContainer.style.background = 'rgba(0, 0, 0, 0.75)';
    uiContainer.style.padding = '12px 20px';
    uiContainer.style.borderRadius = '12px';
    uiContainer.style.display = 'flex';
    uiContainer.style.gap = '12px';
    uiContainer.style.alignItems = 'center';
    uiContainer.style.flexWrap = 'wrap';
    uiContainer.style.justifyContent = 'center';
    uiContainer.style.backdropFilter = 'blur(4px)';

    const timeInput = document.createElement('input');
    timeInput.type = 'time';
    timeInput.value = presetAlarmTime;
    timeInput.style.border = 'none';
    timeInput.style.borderRadius = '6px';
    timeInput.style.padding = '8px';
    timeInput.style.fontSize = '16px';
    timeInput.style.outline = 'none';
    timeInput.style.cursor = 'text';

    const toggleBtn = document.createElement('button');
    toggleBtn.textContent = 'Set Alarm';
    toggleBtn.style.padding = '8px 16px';
    toggleBtn.style.fontSize = '16px';
    toggleBtn.style.backgroundColor = '#4caf50';
    toggleBtn.style.color = '#ffffff';
    toggleBtn.style.border = 'none';
    toggleBtn.style.borderRadius = '6px';
    toggleBtn.style.cursor = 'pointer';
    toggleBtn.style.fontWeight = 'bold';
    toggleBtn.style.transition = 'background-color 0.2s';

    uiContainer.appendChild(timeInput);
    uiContainer.appendChild(toggleBtn);
    container.appendChild(uiContainer);

    // Alarm state variables
    let alarmSet = false;
    let alarmRinging = false;
    let audioCtx = null;
    let beepInterval = null;

    function playAlarm() {
        if (!audioCtx && typeof window.AudioContext !== 'undefined') {
            const AudioContext = window.AudioContext || window.webkitAudioContext;
            audioCtx = new AudioContext();
        }
        if (audioCtx && audioCtx.state === 'suspended') {
            audioCtx.resume();
        }

        function beep() {
            if (!alarmRinging || !audioCtx) return;
            const osc = audioCtx.createOscillator();
            const gain = audioCtx.createGain();
            osc.type = 'square';
            osc.frequency.setValueAtTime(880, audioCtx.currentTime); // 880Hz beep
            
            osc.connect(gain);
            gain.connect(audioCtx.destination);
            
            osc.start(audioCtx.currentTime);
            osc.stop(audioCtx.currentTime + 0.15); // Beep for 150ms
            
            setTimeout(() => {
                if (!alarmRinging) return;
                const osc2 = audioCtx.createOscillator();
                const gain2 = audioCtx.createGain();
                osc2.type = 'square';
                osc2.frequency.setValueAtTime(880, audioCtx.currentTime);
                osc2.connect(gain2);
                gain2.connect(audioCtx.destination);
                osc2.start(audioCtx.currentTime);
                osc2.stop(audioCtx.currentTime + 0.15);
            }, 250); 
        }

        beep();
        beepInterval = setInterval(beep, 1000);
    }

    function stopAlarm() {
        alarmRinging = false;
        if (beepInterval) {
            clearInterval(beepInterval);
            beepInterval = null;
        }
    }

    toggleBtn.addEventListener('click', () => {
        if (alarmRinging) {
            stopAlarm();
            toggleBtn.textContent = 'Set Alarm';
            toggleBtn.style.backgroundColor = '#4caf50';
            alarmSet = false;
        } else if (alarmSet) {
            alarmSet = false;
            toggleBtn.textContent = 'Set Alarm';
            toggleBtn.style.backgroundColor = '#4caf50';
        } else {
            if (!timeInput.value) return; 
            alarmSet = true;
            toggleBtn.textContent = 'Cancel Alarm';
            toggleBtn.style.backgroundColor = '#ff9800';
            
            // Initialize/Resume AudioContext on user interaction
            if (!audioCtx && typeof window.AudioContext !== 'undefined') {
                const AudioContext = window.AudioContext || window.webkitAudioContext;
                audioCtx = new AudioContext();
            }
            if (audioCtx && audioCtx.state === 'suspended') {
                audioCtx.resume();
            }
        }
    });

    let frameId;
    let flash = false;
    let lastFlashTime = 0;

    function render() {
        // Draw image background
        ctx.clearRect(0, 0, canvasWidth, canvasHeight);
        ctx.drawImage(originalImg, 0, 0);

        // Darken overlay for better clock visibility
        ctx.fillStyle = 'rgba(0, 0, 0, 0.4)';
        ctx.fillRect(0, 0, canvasWidth, canvasHeight);

        const now = new Date();
        const hours = now.getHours();
        const minutes = now.getMinutes();
        const seconds = now.getSeconds();

        // Check alarm match
        if (alarmSet && !alarmRinging) {
            const [alarmH, alarmM] = timeInput.value.split(':').map(Number);
            if (hours === alarmH && minutes === alarmM) {
                alarmRinging = true;
                alarmSet = false;
                toggleBtn.textContent = 'Stop Alarm!';
                toggleBtn.style.backgroundColor = '#f44336';
                playAlarm();
            }
        }

        // Flashing screen effect when ringing
        if (alarmRinging) {
            const timeSinceFlash = Date.now() - lastFlashTime;
            if (timeSinceFlash > 400) {
                flash = !flash;
                lastFlashTime = Date.now();
            }
            if (flash) {
                ctx.fillStyle = 'rgba(255, 0, 0, 0.25)';
                ctx.fillRect(0, 0, canvasWidth, canvasHeight);
            }
        }

        const minDim = Math.min(canvasWidth, canvasHeight);
        const centerX = canvasWidth / 2;
        const centerY = canvasHeight / 2 - (minDim * 0.05);

        // Draw Clock
        if (clockFormat.toLowerCase() === 'analog') {
            const radius = Math.max(minDim * 0.35, 60);

            // Shadow for contrast
            ctx.shadowColor = "rgba(0, 0, 0, 0.8)";
            ctx.shadowBlur = 15;
            ctx.shadowOffsetX = 5;
            ctx.shadowOffsetY = 5;

            // Draw Face
            ctx.beginPath();
            ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
            ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';
            ctx.fill();
            ctx.lineWidth = radius * 0.05;
            ctx.strokeStyle = '#222';
            ctx.stroke();

            ctx.shadowColor = "transparent";

            // Draw Numbers
            ctx.font = `bold ${radius * 0.25}px Arial`;
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillStyle = '#222';
            for (let i = 1; i <= 12; i++) {
                const angle = (i * Math.PI / 6) - (Math.PI / 2);
                const x = centerX + Math.cos(angle) * radius * 0.78;
                const y = centerY + Math.sin(angle) * radius * 0.78;
                ctx.fillText(i.toString(), x, y);
            }

            // Draw Hands Helper
            function drawHand(value, max, length, width, color) {
                const angle = (value * 2 * Math.PI / max) - (Math.PI / 2);
                ctx.beginPath();
                ctx.moveTo(centerX, centerY);
                ctx.lineTo(centerX + Math.cos(angle) * length, centerY + Math.sin(angle) * length);
                ctx.lineWidth = width;
                ctx.strokeStyle = color;
                ctx.lineCap = 'round';
                ctx.stroke();
            }

            // Draw Time
            drawHand((hours % 12) + minutes / 60, 12, radius * 0.5, radius * 0.08, '#222'); // Hour
            drawHand(minutes + seconds / 60, 60, radius * 0.7, radius * 0.05, '#555');      // Minute
            drawHand(seconds, 60, radius * 0.85, radius * 0.02, '#e74c3c');                 // Second

            // Center Pin
            ctx.beginPath();
            ctx.arc(centerX, centerY, radius * 0.05, 0, 2 * Math.PI);
            ctx.fillStyle = '#222';
            ctx.fill();
            
        } else {
            // Digital Clock
            const timeStr = [
                hours.toString().padStart(2, '0'),
                minutes.toString().padStart(2, '0'),
                seconds.toString().padStart(2, '0')
            ].join(':');

            const timeFontSize = Math.max(minDim * 0.18, 40);
            ctx.font = `bold ${timeFontSize}px "Courier New", Courier, monospace`;
            
            // Text shadow for high contrast over any image
            ctx.shadowColor = "rgba(0, 0, 0, 0.9)";
            ctx.shadowBlur = 10;
            ctx.shadowOffsetX = 3;
            ctx.shadowOffsetY = 3;
            
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillStyle = (alarmRinging && flash) ? '#ff5252' : '#ffffff';
            ctx.fillText(timeStr, centerX, centerY);
            
            // Draw Date
            const dateStr = now.toLocaleDateString();
            ctx.font = `bold ${timeFontSize * 0.3}px sans-serif`;
            ctx.fillStyle = '#ddd';
            ctx.fillText(dateStr, centerX, centerY + timeFontSize * 0.8);
            
            ctx.shadowColor = "transparent";
        }

        // Status Text (Top area)
        ctx.font = `bold ${Math.max(minDim * 0.06, 16)}px sans-serif`;
        ctx.textAlign = 'center';
        ctx.shadowColor = "rgba(0, 0, 0, 0.8)";
        ctx.shadowBlur = 5;
        
        let statusText = '';
        if (alarmRinging) {
            ctx.fillStyle = '#ff5252';
            statusText = 'WAKE UP! ALARM IS RINGING!';
        } else if (alarmSet) {
            ctx.fillStyle = '#69f0ae';
            statusText = `Alarm Scheduled for ${timeInput.value}`;
        }
        
        if (statusText) {
            const offsetMultiplier = clockFormat.toLowerCase() === 'analog' ? 0.38 : 0.25;
            ctx.fillText(statusText, centerX, (canvasHeight / 2) - (minDim * offsetMultiplier));
        }
        
        ctx.shadowColor = "transparent";
        frameId = requestAnimationFrame(render);
    }

    render();

    // Ensure the intervals and animations are stopped if the element loses track, though in HTML usage returning the UI handles its lifecycle
    return container;
}

Free Image Tool Creator

Can't find the image tool you're looking for?
Create one based on your own needs now!

Description

The Image Alarm Clock Tool allows users to transform any uploaded image into a functional, visual alarm clock. The tool overlays a real-time clock—available in either digital or analog formats—directly onto your chosen image. It features a built-in alarm system where you can set a specific time, which will trigger an audible beep and a flashing screen effect when reached. This tool is ideal for creating personalized digital clocks, themed desktop backgrounds with time tracking, or engaging visual timers for various settings.

Leave a Reply

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