One Page Tools

Your Advertisement Here (e.g., 728x90 Leaderboard)

Advertisement

Welcome to One Page Tools: Your Ultimate Online Toolkit

In today's fast-paced digital world, efficiency and convenience are paramount. Whether you're a student, a professional, a content creator, or simply someone who interacts with digital media and data regularly, having quick access to a versatile set of tools can be a game-changer. That's where One Page Tools comes in. We've curated a collection of 20 essential, free-to-use online tools designed to simplify your tasks, boost your productivity, and empower your digital endeavors – all from the comfort of your web browser, with no installations required and a strong focus on client-side processing for speed and privacy.

Our platform is built with a modern, premium, and minimalistic design, ensuring a seamless and enjoyable user experience across all devices – desktop, tablet, and mobile. Each tool is crafted to be fully functional using only HTML, CSS, and Vanilla JavaScript, meaning they are lightweight, fast, and respect your privacy by processing data directly in your browser whenever possible.

Why Choose One Page Tools?

Explore Our Suite of 20 Powerful Tools:

🎨 Image Manipulation Tools

Perfect for designers, photographers, and anyone working with digital images.

1. Image Converter

What it does: Easily convert your images between popular formats like JPG, PNG, and WEBP. Whether you need a transparent background (PNG), a highly compressed web-friendly format (WEBP), or a standard photographic format (JPG), this tool handles it swiftly using browser-native canvas technology.

Use cases: Preparing images for web use, changing formats for compatibility, optimizing image types for specific needs.

2. Image Compressor

What it does: Reduce the file size of your images without significant loss of quality. This tool uses canvas and adjustable quality settings (for JPEGs) to make your images lighter, faster to load on websites, and easier to share.

Use cases: Optimizing website images for faster loading times, reducing storage space, sending images via email or messaging apps with size limits.

3. Image Cropper

What it does: Upload an image, define your desired crop area with a visual preview, and export the perfectly cropped section. Ideal for focusing on specific parts of an image or adjusting aspect ratios.

Use cases: Creating profile pictures, framing subjects, removing unwanted parts of an image, preparing images for specific layouts.

🎬 Audio & Video Tools

For content creators, students, or anyone needing to tweak audio and video files.

4. Video Converter (Browser-Limited)

What it does: Convert video formats (e.g., MP4 to WebM or vice-versa) by re-encoding the video directly in your browser using MediaRecorder or canvas capabilities. Functionality and output quality depend on your browser's support for these technologies.

Use cases: Making videos compatible with specific platforms or devices, converting to web-friendly formats. (Note: Browser capabilities are key here).

5. Audio Converter (to WAV)

What it does: Convert various audio files that your browser can play into the versatile WAV format. This tool utilizes the Web Audio API for decoding and processing.

Use cases: Preparing audio for editing software that prefers WAV, standardizing audio formats, creating uncompressed audio clips.

6. Audio Trimmer

What it does: Upload an audio file, specify start and end times, and export the trimmed segment as a new WAV clip. Perfect for extracting soundbites, creating ringtones, or shortening audio recordings.

Use cases: Editing podcasts or interviews, creating short audio samples, removing unwanted sections from recordings.

🧮 Productivity & Financial Calculators

Essential tools for everyday calculations, financial planning, and health monitoring.

7. Age Calculator

What it does: Simply input a date of birth, and this tool will instantly calculate the age in years, months, and days. Accurate and quick.

Use cases: Finding exact age for forms or records, curiosity, event planning based on age milestones.

8. EMI Calculator

What it does: Plan your loans effectively. Input the loan amount, annual interest rate, and loan duration (in months) to calculate your Equated Monthly Installment (EMI), total interest payable, and total payment.

Use cases: Financial planning for home loans, car loans, personal loans; understanding loan affordability.

9. SIP Calculator

What it does: Estimate the future value of your Systematic Investment Plan (SIP) investments. Enter your monthly investment amount, expected annual interest rate, and investment duration (in years) to see potential returns.

Use cases: Mutual fund investment planning, retirement planning, goal-based savings projections.

10. BMI Calculator

What it does: Calculate your Body Mass Index (BMI) by entering your weight (in kg) and height (in cm). The tool also provides your BMI category (e.g., Underweight, Normal, Overweight).

Use cases: Health and fitness tracking, understanding weight status, a general indicator for health assessment (consult a professional for medical advice).

✒️ Text & Code Utilities

A must-have for writers, developers, and anyone dealing with text or data.

11. QR Code Generator

What it does: Enter any text, URL, contact information, or Wi-Fi credentials, and generate a downloadable QR code image instantly. Uses canvas for generation.

Use cases: Sharing website links, contact details, Wi-Fi access easily; marketing materials, event ticketing.

12. Password Generator

What it does: Create strong, secure, and random passwords. Customize the length and include/exclude uppercase letters, lowercase letters, numbers, and symbols to meet various security requirements.

Use cases: Enhancing online security, creating unique passwords for different accounts, adhering to password complexity rules.

13. Word Counter

What it does: A real-time text analysis tool. As you type or paste text, it counts words, characters (with and without spaces), spaces, and even estimates reading time. Essential for writers, students, and social media managers.

Use cases: Meeting word count requirements for essays or articles, optimizing social media posts, tracking writing progress.

14. Base64 Encoder/Decoder

What it does: Easily convert plain text to Base64 encoding or decode Base64 strings back to their original plain text form. Useful for data transmission or simple obfuscation.

Use cases: Encoding data for URLs or HTML, decoding data from various web sources, simple data protection (not encryption).

15. JSON Formatter

What it does: Paste your JSON data, and this tool will auto-format (pretty-print) it with proper indentation and syntax highlighting. It also helps validate the JSON structure and points out errors.

Use cases: Debugging JSON APIs, making complex JSON data readable, validating JSON structures before use in applications.

🗣️ Accessibility & Interactive Tools

Enhance accessibility and engage with content in new ways.

16. Color Picker Tool

What it does: Visually pick a color using a standard color input, or enter a color code. The tool displays its HEX, RGB, and HSL values, making it easy to work with colors for web design, graphic design, or any digital project.

Use cases: Web development, graphic design, digital art, matching colors, understanding color codes.

17. Text to Speech

What it does: Enter any text, and listen to it being read aloud by your browser's built-in speech synthesis engine. You can often choose from different voices, and adjust the rate and pitch.

Use cases: Accessibility for visually impaired users, proofreading text, learning pronunciation, multitasking by listening to content.

18. Speech to Text

What it does: Use your microphone to convert your spoken words into text. This tool leverages your browser's Web Speech API for real-time voice recognition.

Use cases: Dictating notes, writing emails hands-free, accessibility for users with motor impairments, transcribing short audio clips.

📏 Measurement & Time Management Tools

Practical utilities for conversions and keeping track of time.

19. Unit Converter

What it does: A versatile converter for various units of measurement, including length (meters, feet, miles, etc.), weight (kilograms, pounds, ounces, etc.), and temperature (Celsius, Fahrenheit, Kelvin). Simple and intuitive.

Use cases: Converting recipes, scientific calculations, travel planning, everyday measurement conversions.

20. Timer / Stopwatch Tool

What it does: A dual-function tool. Set a countdown timer for tasks or use the stopwatch with lap functionality to measure elapsed time accurately. Clean interface and easy controls.

Use cases: Time management (Pomodoro technique), cooking, workouts, tracking time for activities, conducting experiments.

Privacy and Security at the Forefront

We understand the importance of your data. That's why One Page Tools is designed with a "privacy-first" approach. Many of our tools, particularly those that handle files (like image and audio converters/compressors/croppers), perform all operations directly within your browser. This means your files are not uploaded to our servers, offering you enhanced security and speed. For tools that require input (like calculators or text utilities), the data is processed client-side and is not stored or tracked beyond what's necessary for the tool's immediate function or basic anonymous usage analytics (if enabled by you).

Constantly Evolving

One Page Tools is a living project. We are committed to maintaining and improving our existing tools and potentially adding new ones based on user needs and technological advancements. Our goal is to be your go-to destination for quick, reliable, and free online utilities.

We invite you to explore the One Page Tools and discover how our suite of tools can simplify your digital life. Bookmark us and share with friends and colleagues who might benefit from these handy utilities!

Your Advertisement Here (e.g., 728x90 or 300x250)
"> One Page Tools - Your Ultimate Collection of Free Online Tools

One Page Tools

Your Advertisement Here (e.g., 728x90 Leaderboard)

Welcome to One Page Tools: Your Ultimate Online Toolkit

In today's fast-paced digital world, efficiency and convenience are paramount. Whether you're a student, a professional, a content creator, or simply someone who interacts with digital media and data regularly, having quick access to a versatile set of tools can be a game-changer. That's where One Page Tools comes in. We've curated a collection of 20 essential, free-to-use online tools designed to simplify your tasks, boost your productivity, and empower your digital endeavors – all from the comfort of your web browser, with no installations required and a strong focus on client-side processing for speed and privacy.

Our platform is built with a modern, premium, and minimalistic design, ensuring a seamless and enjoyable user experience across all devices – desktop, tablet, and mobile. Each tool is crafted to be fully functional using only HTML, CSS, and Vanilla JavaScript, meaning they are lightweight, fast, and respect your privacy by processing data directly in your browser whenever possible.

Why Choose One Page Tools?

Explore Our Suite of 20 Powerful Tools:

🎨 Image Manipulation Tools

Perfect for designers, photographers, and anyone working with digital images.

1. Image Converter

What it does: Easily convert your images between popular formats like JPG, PNG, and WEBP. Whether you need a transparent background (PNG), a highly compressed web-friendly format (WEBP), or a standard photographic format (JPG), this tool handles it swiftly using browser-native canvas technology.

Use cases: Preparing images for web use, changing formats for compatibility, optimizing image types for specific needs.

2. Image Compressor

What it does: Reduce the file size of your images without significant loss of quality. This tool uses canvas and adjustable quality settings (for JPEGs) to make your images lighter, faster to load on websites, and easier to share.

Use cases: Optimizing website images for faster loading times, reducing storage space, sending images via email or messaging apps with size limits.

3. Image Cropper

What it does: Upload an image, define your desired crop area with a visual preview, and export the perfectly cropped section. Ideal for focusing on specific parts of an image or adjusting aspect ratios.

Use cases: Creating profile pictures, framing subjects, removing unwanted parts of an image, preparing images for specific layouts.

🎬 Audio & Video Tools

For content creators, students, or anyone needing to tweak audio and video files.

4. Video Converter (Browser-Limited)

What it does: Convert video formats (e.g., MP4 to WebM or vice-versa) by re-encoding the video directly in your browser using MediaRecorder or canvas capabilities. Functionality and output quality depend on your browser's support for these technologies.

Use cases: Making videos compatible with specific platforms or devices, converting to web-friendly formats. (Note: Browser capabilities are key here).

5. Audio Converter (to WAV)

What it does: Convert various audio files that your browser can play into the versatile WAV format. This tool utilizes the Web Audio API for decoding and processing.

Use cases: Preparing audio for editing software that prefers WAV, standardizing audio formats, creating uncompressed audio clips.

6. Audio Trimmer

What it does: Upload an audio file, specify start and end times, and export the trimmed segment as a new WAV clip. Perfect for extracting soundbites, creating ringtones, or shortening audio recordings.

Use cases: Editing podcasts or interviews, creating short audio samples, removing unwanted sections from recordings.

🧮 Productivity & Financial Calculators

Essential tools for everyday calculations, financial planning, and health monitoring.

7. Age Calculator

What it does: Simply input a date of birth, and this tool will instantly calculate the age in years, months, and days. Accurate and quick.

Use cases: Finding exact age for forms or records, curiosity, event planning based on age milestones.

8. EMI Calculator

What it does: Plan your loans effectively. Input the loan amount, annual interest rate, and loan duration (in months) to calculate your Equated Monthly Installment (EMI), total interest payable, and total payment.

Use cases: Financial planning for home loans, car loans, personal loans; understanding loan affordability.

9. SIP Calculator

What it does: Estimate the future value of your Systematic Investment Plan (SIP) investments. Enter your monthly investment amount, expected annual interest rate, and investment duration (in years) to see potential returns.

Use cases: Mutual fund investment planning, retirement planning, goal-based savings projections.

10. BMI Calculator

What it does: Calculate your Body Mass Index (BMI) by entering your weight (in kg) and height (in cm). The tool also provides your BMI category (e.g., Underweight, Normal, Overweight).

Use cases: Health and fitness tracking, understanding weight status, a general indicator for health assessment (consult a professional for medical advice).

✒️ Text & Code Utilities

A must-have for writers, developers, and anyone dealing with text or data.

11. QR Code Generator

What it does: Enter any text, URL, contact information, or Wi-Fi credentials, and generate a downloadable QR code image instantly. Uses canvas for generation.

Use cases: Sharing website links, contact details, Wi-Fi access easily; marketing materials, event ticketing.

12. Password Generator

What it does: Create strong, secure, and random passwords. Customize the length and include/exclude uppercase letters, lowercase letters, numbers, and symbols to meet various security requirements.

Use cases: Enhancing online security, creating unique passwords for different accounts, adhering to password complexity rules.

13. Word Counter

What it does: A real-time text analysis tool. As you type or paste text, it counts words, characters (with and without spaces), spaces, and even estimates reading time. Essential for writers, students, and social media managers.

Use cases: Meeting word count requirements for essays or articles, optimizing social media posts, tracking writing progress.

14. Base64 Encoder/Decoder

What it does: Easily convert plain text to Base64 encoding or decode Base64 strings back to their original plain text form. Useful for data transmission or simple obfuscation.

Use cases: Encoding data for URLs or HTML, decoding data from various web sources, simple data protection (not encryption).

15. JSON Formatter

What it does: Paste your JSON data, and this tool will auto-format (pretty-print) it with proper indentation and syntax highlighting. It also helps validate the JSON structure and points out errors.

Use cases: Debugging JSON APIs, making complex JSON data readable, validating JSON structures before use in applications.

🗣️ Accessibility & Interactive Tools

Enhance accessibility and engage with content in new ways.

16. Color Picker Tool

What it does: Visually pick a color using a standard color input, or enter a color code. The tool displays its HEX, RGB, and HSL values, making it easy to work with colors for web design, graphic design, or any digital project.

Use cases: Web development, graphic design, digital art, matching colors, understanding color codes.

17. Text to Speech

What it does: Enter any text, and listen to it being read aloud by your browser's built-in speech synthesis engine. You can often choose from different voices, and adjust the rate and pitch.

Use cases: Accessibility for visually impaired users, proofreading text, learning pronunciation, multitasking by listening to content.

18. Speech to Text

What it does: Use your microphone to convert your spoken words into text. This tool leverages your browser's Web Speech API for real-time voice recognition.

Use cases: Dictating notes, writing emails hands-free, accessibility for users with motor impairments, transcribing short audio clips.

📏 Measurement & Time Management Tools

Practical utilities for conversions and keeping track of time.

19. Unit Converter

What it does: A versatile converter for various units of measurement, including length (meters, feet, miles, etc.), weight (kilograms, pounds, ounces, etc.), and temperature (Celsius, Fahrenheit, Kelvin). Simple and intuitive.

Use cases: Converting recipes, scientific calculations, travel planning, everyday measurement conversions.

20. Timer / Stopwatch Tool

What it does: A dual-function tool. Set a countdown timer for tasks or use the stopwatch with lap functionality to measure elapsed time accurately. Clean interface and easy controls.

Use cases: Time management (Pomodoro technique), cooking, workouts, tracking time for activities, conducting experiments.

Privacy and Security at the Forefront

We understand the importance of your data. That's why One Page Tools is designed with a "privacy-first" approach. Many of our tools, particularly those that handle files (like image and audio converters/compressors/croppers), perform all operations directly within your browser. This means your files are not uploaded to our servers, offering you enhanced security and speed. For tools that require input (like calculators or text utilities), the data is processed client-side and is not stored or tracked beyond what's necessary for the tool's immediate function or basic anonymous usage analytics (if enabled by you).

Constantly Evolving

One Page Tools is a living project. We are committed to maintaining and improving our existing tools and potentially adding new ones based on user needs and technological advancements. Our goal is to be your go-to destination for quick, reliable, and free online utilities.

We invite you to explore the One Page Tools and discover how our suite of tools can simplify your digital life. Bookmark us and share with friends and colleagues who might benefit from these handy utilities!

Your Advertisement Here (e.g., 728x90 or 300x250)
data-ad-slot="YOUR_ADMOB_SLOT"> // write WAVE header view.setUint32(pos, 0x46464952, false); pos += 4; // "RIFF" view.setUint32(pos, length - 8, true); pos += 4; // file length - 8 view.setUint32(pos, 0x45564157, false); pos += 4; // "WAVE" view.setUint32(pos, 0x20746d66, false); pos += 4; // "fmt " chunk view.setUint32(pos, 16, true); pos += 4; // length = 16 view.setUint16(pos, 1, true); pos += 2; // PCM (uncompressed) view.setUint16(pos, numOfChan, true); pos += 2; view.setUint32(pos, abuffer.sampleRate, true); pos += 4; view.setUint32(pos, abuffer.sampleRate * 2 * numOfChan, true); pos += 4; // "byte rate" view.setUint16(pos, numOfChan * 2, true); pos += 2; // block align (channels * bytes/sample) view.setUint16(pos, 16, true); pos += 2; // bits per sample view.setUint32(pos, 0x61746164, false); pos += 4; // "data" - chunk view.setUint32(pos, abuffer.length * numOfChan * 2, true); pos += 4; // chunk length (audio data size) for (i = 0; i < abuffer.numberOfChannels; i++) channels.push(abuffer.getChannelData(i)); // Write interleaved data for (offset = 0; offset < abuffer.length; offset++) { for (i = 0; i < numOfChan; i++) { sample = Math.max(-1, Math.min(1, channels[i][offset])); // clamp sample = sample < 0 ? sample * 0x8000 : sample * 0x7FFF; // scale to 16-bit signed int view.setInt16(pos, sample, true); pos += 2; } } return new Blob([view], { type: 'audio/wav' }); } return (container) => { // This is the actual toolInitializer function container.innerHTML = `

This tool converts various audio formats (that your browser can play) into WAV format.

`; const fileInput = container.querySelector('#audioConvFile'); const convertButton = container.querySelector('#audioConvButton'); const audioPreview = container.querySelector('#audioConvPreview'); let decodedAudioBuffer = null; // Renamed to avoid conflict let originalFileName = 'converted_audio'; fileInput.onchange = (e) => { if (e.target.files && e.target.files[0]) { const file = e.target.files[0]; originalFileName = file.name.split('.')[0] || 'audio'; showAlert('Loading audio...', 'info'); const reader = new FileReader(); reader.onload = (event) => { audioContext.decodeAudioData(event.target.result) .then(buffer => { // Changed var name here decodedAudioBuffer = buffer; // Create a temporary URL for preview to avoid issues with large files / ArrayBuffer const tempUrl = URL.createObjectURL(file); audioPreview.src = tempUrl; audioPreview.style.display = 'block'; audioPreview.oncanplaythrough = () => URL.revokeObjectURL(tempUrl); // Revoke after load showAlert('Audio loaded. Ready to convert to WAV.', 'success'); }) .catch(err => showAlert(`Error decoding audio: ${err.message}. Try a different format.`, 'error')); }; reader.onerror = () => showAlert('Error reading file.', 'error'); reader.readAsArrayBuffer(file); } else { audioPreview.style.display = 'none'; audioPreview.src = ""; decodedAudioBuffer = null; } }; convertButton.onclick = () => { if (!decodedAudioBuffer) { showAlert('Please select and load an audio file first.', 'error'); return; } showAlert('Converting to WAV...', 'info'); try { const wavBlob = bufferToWave(decodedAudioBuffer); // Use the shared function const url = URL.createObjectURL(wavBlob); const a = document.createElement('a'); a.href = url; a.download = `${originalFileName}_converted.wav`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); showAlert('Conversion to WAV successful!', 'success'); } catch (err) { showAlert(`Error converting to WAV: ${err.message}`, 'error'); } }; // Make bufferToWave accessible for the trimmer toolInitializers.audioConverter.bufferToWave = bufferToWave; window.currentToolCleanup = () => { if (audioPreview && audioPreview.src && audioPreview.src.startsWith('blob:')) { URL.revokeObjectURL(audioPreview.src); } }; }; })(), // Immediately invoke the IIFE audioTrimmer: (container) => { const audioContext = new (window.AudioContext || window.webkitAudioContext)(); container.innerHTML = ` `; const fileInput = container.querySelector('#trimAudioFile'); const audioPreview = container.querySelector('#trimAudioPreview'); const trimControls = container.querySelector('#trimControls'); const startTimeInput = container.querySelector('#trimStartTime'); const endTimeInput = container.querySelector('#trimEndTime'); const durationInfo = container.querySelector('#audioDurationInfo'); const trimButton = container.querySelector('#trimButton'); let sourceBuffer = null; let originalFileName = 'trimmed_audio'; fileInput.onchange = (e) => { if (e.target.files && e.target.files[0]) { const file = e.target.files[0]; originalFileName = file.name.split('.')[0] || 'audio'; showAlert('Loading audio...', 'info'); const reader = new FileReader(); reader.onload = (event) => { audioContext.decodeAudioData(event.target.result) .then(decodedBuffer => { sourceBuffer = decodedBuffer; const tempUrl = URL.createObjectURL(file); audioPreview.src = tempUrl; audioPreview.style.display = 'block'; audioPreview.onloadedmetadata = () => { URL.revokeObjectURL(tempUrl); // Revoke after duration is known const duration = sourceBuffer.duration; // Use buffer duration for accuracy durationInfo.textContent = `Duration: ${duration.toFixed(2)}s`; endTimeInput.value = duration.toFixed(2); endTimeInput.max = duration.toFixed(2); startTimeInput.max = duration.toFixed(2); trimControls.style.display = 'block'; showAlert('Audio loaded. Set trim times.', 'success'); }; audioPreview.onerror = () => showAlert('Error playing preview.', 'error'); }) .catch(err => showAlert(`Error decoding audio: ${err.message}`, 'error')); }; reader.readAsArrayBuffer(file); } else { audioPreview.style.display = 'none'; trimControls.style.display = 'none'; audioPreview.src = ""; sourceBuffer = null; } }; trimButton.onclick = () => { if (!sourceBuffer) { showAlert('Please load an audio file first.', 'error'); return; } const startTime = parseFloat(startTimeInput.value); const endTime = parseFloat(endTimeInput.value); if (isNaN(startTime) || isNaN(endTime) || startTime < 0 || endTime <= startTime || endTime > sourceBuffer.duration) { showAlert('Invalid start/end times. Ensure End Time is after Start Time and within audio duration.', 'error'); return; } showAlert('Trimming audio...', 'info'); try { const startOffset = Math.floor(startTime * sourceBuffer.sampleRate); const endOffset = Math.floor(endTime * sourceBuffer.sampleRate); const frameCount = endOffset - startOffset; if (frameCount <=0) { showAlert('Trimmed duration is zero or negative.', 'error'); return; } const trimmedBuffer = audioContext.createBuffer( sourceBuffer.numberOfChannels, frameCount, sourceBuffer.sampleRate ); for (let i = 0; i < sourceBuffer.numberOfChannels; i++) { const channelData = sourceBuffer.getChannelData(i); const trimmedChannelData = trimmedBuffer.getChannelData(i); // Use subarray correctly: source.subarray(begin, end) trimmedChannelData.set(channelData.subarray(startOffset, endOffset)); } if (typeof toolInitializers.audioConverter.bufferToWave !== 'function') { showAlert('Audio conversion utility not found.', 'error'); return; } const wavBlob = toolInitializers.audioConverter.bufferToWave(trimmedBuffer); const url = URL.createObjectURL(wavBlob); const a = document.createElement('a'); a.href = url; a.download = `${originalFileName}_trimmed.wav`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); showAlert('Audio trimmed and downloaded!', 'success'); } catch (err) { showAlert(`Error trimming audio: ${err.message}`, 'error'); console.error("Trimming error:", err); } }; window.currentToolCleanup = () => { if (audioPreview && audioPreview.src && audioPreview.src.startsWith('blob:')) { URL.revokeObjectURL(audioPreview.src); } }; }, // ... (The rest of the toolInitializers from the previous response) ... // --- Age Calculator --- ageCalculator: (container) => { container.innerHTML = ` `; const birthDateInput = container.querySelector('#birthDate'); const calculateBtn = container.querySelector('#calculateAgeBtn'); const ageResultDiv = container.querySelector('#ageResult'); calculateBtn.onclick = () => { const birthDateString = birthDateInput.value; if (!birthDateString) { showAlert('Please enter your date of birth.', 'error'); ageResultDiv.style.display = 'none'; return; } const birthDate = new Date(birthDateString); const today = new Date(); if (birthDate > today) { showAlert('Birth date cannot be in the future.', 'error'); ageResultDiv.style.display = 'none'; return; } let years = today.getFullYear() - birthDate.getFullYear(); let months = today.getMonth() - birthDate.getMonth(); let days = today.getDate() - birthDate.getDate(); if (days < 0) { months--; // Get days in the previous month of 'today' const prevMonth = new Date(today.getFullYear(), today.getMonth(), 0); days += prevMonth.getDate(); } if (months < 0) { years--; months += 12; } ageResultDiv.innerHTML = `You are:
${years} years, ${months} months, and ${days} days old.`; ageResultDiv.style.display = 'block'; hideAlert(); }; }, // --- EMI Calculator --- emiCalculator: (container) => { container.innerHTML = ` `; const amountInput = container.querySelector('#loanAmount'); const rateInput = container.querySelector('#interestRate'); const tenureInput = container.querySelector('#loanTenure'); const calculateBtn = container.querySelector('#calculateEmiBtn'); const resultDiv = container.querySelector('#emiResult'); calculateBtn.onclick = () => { const P = parseFloat(amountInput.value); const annualRate = parseFloat(rateInput.value); const N = parseInt(tenureInput.value); if (isNaN(P) || isNaN(annualRate) || isNaN(N) || P <= 0 || annualRate < 0 || N <= 0) { showAlert('Please enter valid positive numbers for amount & tenure, and a non-negative rate.', 'error'); resultDiv.style.display = 'none'; return; } if (annualRate === 0) { // Handle zero interest rate const EMI = P / N; resultDiv.innerHTML = `Monthly EMI: ₹${EMI.toFixed(2)}
Total Interest Payable: ₹0.00
Total Payment (Principal + Interest): ₹${P.toFixed(2)}`; resultDiv.style.display = 'block'; hideAlert(); return; } const r = annualRate / (12 * 100); // Monthly interest rate const EMI = (P * r * Math.pow(1 + r, N)) / (Math.pow(1 + r, N) - 1); const totalPayment = EMI * N; const totalInterest = totalPayment - P; if (!isFinite(EMI)) { showAlert('Calculation resulted in an invalid number. Please check your inputs.', 'error'); resultDiv.style.display = 'none'; return; } resultDiv.innerHTML = `Monthly EMI: ₹${EMI.toFixed(2)}
Total Interest Payable: ₹${totalInterest.toFixed(2)}
Total Payment (Principal + Interest): ₹${totalPayment.toFixed(2)}`; resultDiv.style.display = 'block'; hideAlert(); }; }, // --- SIP Calculator --- sipCalculator: (container) => { container.innerHTML = ` `; const monthlyInvestmentInput = container.querySelector('#monthlyInvestment'); const returnRateInput = container.querySelector('#expectedReturnRate'); const durationInput = container.querySelector('#investmentDuration'); const calculateBtn = container.querySelector('#calculateSipBtn'); const resultDiv = container.querySelector('#sipResult'); calculateBtn.onclick = () => { const P = parseFloat(monthlyInvestmentInput.value); const annualRate = parseFloat(returnRateInput.value); const t_years = parseInt(durationInput.value); if (isNaN(P) || isNaN(annualRate) || isNaN(t_years) || P <= 0 || annualRate < 0 || t_years <= 0) { showAlert('Please enter valid positive numbers for investment & duration, and a non-negative rate.', 'error'); resultDiv.style.display = 'none'; return; } const n = t_years * 12; const i = annualRate / 12 / 100; let M; if (i === 0) { // Handle zero interest rate for SIP M = P * n; } else { M = P * ( (Math.pow(1 + i, n) - 1) / i ) * (1 + i); } const totalInvestment = P * n; const wealthGained = M - totalInvestment; resultDiv.innerHTML = `Invested Amount: ₹${totalInvestment.toFixed(2)}
Estimated Returns: ₹${wealthGained.toFixed(2)}
Total Future Value: ₹${M.toFixed(2)}`; resultDiv.style.display = 'block'; hideAlert(); }; }, // --- QR Code Generator --- qrCodeGenerator: (container) => { container.innerHTML = ` `; const textInput = container.querySelector('#qrText'); const sizeInput = container.querySelector('#qrSize'); const generateBtn = container.querySelector('#generateQrBtn'); const qrContainer = container.querySelector('#qrCodeContainer'); const downloadBtn = container.querySelector('#downloadQrBtn'); let qrCanvasInstance = null; // To hold the canvas element itself generateBtn.onclick = () => { const text = textInput.value.trim(); const size = parseInt(sizeInput.value); if (!text) { showAlert('Please enter text or URL for the QR code.', 'error'); qrContainer.style.display = 'none'; downloadBtn.style.display = 'none'; return; } if (isNaN(size) || size < 50 || size > 500) { showAlert('Please enter a valid size between 50 and 500 pixels.', 'error'); return; } qrContainer.innerHTML = ''; // Clear previous QR code try { if (typeof QRCode !== 'undefined') { // Check if a library like qrcode.js is loaded qrCanvasInstance = document.createElement('div'); // qrcode.js typically targets a div qrContainer.appendChild(qrCanvasInstance); new QRCode(qrCanvasInstance, { text: text, width: size, height: size, colorDark : "#000000", colorLight : "#ffffff", correctLevel : QRCode.CorrectLevel.H }); // qrcode.js generates an img and a canvas, we want the canvas for download // Wait a moment for QRCode.js to render setTimeout(() => { const canvasFromLib = qrCanvasInstance.querySelector('canvas'); if (canvasFromLib) { qrCanvasInstance = canvasFromLib; // Now qrCanvasInstance is the actual canvas } else { // Fallback if canvas not found, might be an img tag const imgFromLib = qrCanvasInstance.querySelector('img'); if (imgFromLib) { // Create a canvas from the image const tempCanvas = document.createElement('canvas'); tempCanvas.width = imgFromLib.width; tempCanvas.height = imgFromLib.height; tempCanvas.getContext('2d').drawImage(imgFromLib, 0, 0); qrCanvasInstance = tempCanvas; } } }, 100); showAlert('QR Code generated!', 'success'); } else { // Fallback to simplified canvas drawing if no library qrCanvasInstance = document.createElement('canvas'); qrContainer.appendChild(qrCanvasInstance); const ctx = qrCanvasInstance.getContext('2d'); qrCanvasInstance.width = size; qrCanvasInstance.height = size; ctx.fillStyle = 'white'; ctx.fillRect(0, 0, size, size); ctx.fillStyle = 'black'; ctx.font = `${size/15}px Arial`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; // Simple placeholder text rendering - not a real QR const lines = text.match(/.{1,20}/g) || [text]; // Split text lines.forEach((line, i) => { ctx.fillText(line, size / 2, size / 2 - (lines.length/2 * (size/10)) + (i * (size/10)) ); }); ctx.strokeRect(size*0.1, size*0.1, size*0.8, size*0.8); // Border showAlert('QR Code (placeholder - library not found) generated. For real QR codes, integrate a library.', 'info'); } qrContainer.style.display = 'block'; downloadBtn.style.display = 'inline-block'; } catch (e) { showAlert('Error generating QR code: ' + e.message, 'error'); console.error("QR Gen Error:", e); qrContainer.style.display = 'none'; downloadBtn.style.display = 'none'; } }; downloadBtn.onclick = () => { if (qrCanvasInstance && qrCanvasInstance.tagName === 'CANVAS') { const dataURL = qrCanvasInstance.toDataURL('image/png'); const a = document.createElement('a'); a.href = dataURL; a.download = 'qrcode.png'; document.body.appendChild(a); a.click(); document.body.removeChild(a); } else if (qrCanvasInstance && qrCanvasInstance.tagName === 'IMG') { // If library generated an IMG const a = document.createElement('a'); a.href = qrCanvasInstance.src; a.download = 'qrcode.png'; document.body.appendChild(a); a.click(); document.body.removeChild(a); } else { showAlert('QR Code canvas not available for download.', 'error'); } }; }, // --- Password Generator --- passwordGenerator: (container) => { container.innerHTML = `



`; const lengthInput = container.querySelector('#passLength'); const uppercaseCheck = container.querySelector('#incUppercase'); const lowercaseCheck = container.querySelector('#incLowercase'); const numbersCheck = container.querySelector('#incNumbers'); const symbolsCheck = container.querySelector('#incSymbols'); const generateBtn = container.querySelector('#generatePassBtn'); const passwordOutput = container.querySelector('#generatedPassword'); const copyBtn = container.querySelector('#copyPassBtn'); const charSets = { uppercase: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', lowercase: 'abcdefghijklmnopqrstuvwxyz', numbers: '0123456789', symbols: '!@#$%^&*()_+-=[]{}|;:,.<>?' }; generateBtn.onclick = () => { const length = parseInt(lengthInput.value); let charset = ''; let guaranteedChars = ''; // To ensure at least one char from each selected set if (uppercaseCheck.checked) { charset += charSets.uppercase; guaranteedChars += charSets.uppercase[Math.floor(Math.random() * charSets.uppercase.length)]; } if (lowercaseCheck.checked) { charset += charSets.lowercase; guaranteedChars += charSets.lowercase[Math.floor(Math.random() * charSets.lowercase.length)]; } if (numbersCheck.checked) { charset += charSets.numbers; guaranteedChars += charSets.numbers[Math.floor(Math.random() * charSets.numbers.length)]; } if (symbolsCheck.checked) { charset += charSets.symbols; guaranteedChars += charSets.symbols[Math.floor(Math.random() * charSets.symbols.length)]; } if (charset === '') { showAlert('Please select at least one character type.', 'error'); passwordOutput.value = ''; return; } if (length < 8 || length > 128) { showAlert('Password length must be between 8 and 128.', 'error'); return; } if (length < guaranteedChars.length) { showAlert('Password length is too short to include one of each selected character type.', 'error'); return; } let password = guaranteedChars; for (let i = guaranteedChars.length; i < length; i++) { password += charset.charAt(Math.floor(Math.random() * charset.length)); } // Shuffle the password to make guaranteed characters random password = password.split('').sort(() => 0.5 - Math.random()).join(''); passwordOutput.value = password; hideAlert(); }; copyBtn.onclick = () => { if (passwordOutput.value) { navigator.clipboard.writeText(passwordOutput.value) .then(() => showAlert('Password copied to clipboard!', 'success')) .catch(err => showAlert('Failed to copy password.', 'error')); } }; }, // --- Word Counter --- wordCounter: (container) => { container.innerHTML = `
Words: 0
Characters (with spaces): 0
Characters (no spaces): 0
Spaces: 0
Sentences: 0
Paragraphs: 0
Reading Time: ~0 min
`; const textArea = container.querySelector('#wcText'); const wordsSpan = container.querySelector('#wcWords'); const charsWithSpacesSpan = container.querySelector('#wcCharsWithSpaces'); const charsNoSpacesSpan = container.querySelector('#wcCharsNoSpaces'); const spacesSpan = container.querySelector('#wcSpaces'); const sentencesSpan = container.querySelector('#wcSentences'); const paragraphsSpan = container.querySelector('#wcParagraphs'); const readingTimeSpan = container.querySelector('#wcReadingTime'); textArea.oninput = () => { const text = textArea.value; const wordsArray = text.match(/\b[-'\w]+\b/g); const words = wordsArray ? wordsArray.length : 0; const charsWithSpaces = text.length; const charsNoSpaces = text.replace(/\s+/g, '').length; const spaces = (text.match(/\s/g) || []).length; const sentencesArray = text.match(/[^.!?]+[.!?]+(\s|$)/g); const sentences = sentencesArray ? sentencesArray.length : (text.trim() ? 1: 0); const paragraphsArray = text.split(/\n\s*\n/).filter(p => p.trim() !== ''); const paragraphs = paragraphsArray.length || (text.trim() ? 1:0); const wpm = 200; const readingTimeMinutes = words / wpm; let readingTimeText = ''; if (readingTimeMinutes === 0) { readingTimeText = `~0 min`; } else if (readingTimeMinutes < 1) { const seconds = Math.round(readingTimeMinutes * 60); readingTimeText = `~${seconds} sec`; } else { readingTimeText = `~${Math.ceil(readingTimeMinutes)} min`; } wordsSpan.textContent = words; charsWithSpacesSpan.textContent = charsWithSpaces; charsNoSpacesSpan.textContent = charsNoSpaces; spacesSpan.textContent = spaces; sentencesSpan.textContent = sentences; paragraphsSpan.textContent = paragraphs; readingTimeSpan.textContent = readingTimeText; }; }, // --- Base64 Encoder/Decoder --- base64EncoderDecoder: (container) => { container.innerHTML = ` `; const inputArea = container.querySelector('#b64Input'); const outputArea = container.querySelector('#b64Output'); const encodeBtn = container.querySelector('#b64EncodeBtn'); const decodeBtn = container.querySelector('#b64DecodeBtn'); encodeBtn.onclick = () => { try { // Handle UTF-8 characters correctly for btoa const utf8Encoded = new TextEncoder().encode(inputArea.value); let binaryString = ''; utf8Encoded.forEach(byte => binaryString += String.fromCharCode(byte)); outputArea.value = btoa(binaryString); hideAlert(); } catch (e) { showAlert('Error encoding: ' + e.message, 'error'); outputArea.value = ''; } }; decodeBtn.onclick = () => { try { // Handle UTF-8 characters correctly for atob const binaryString = atob(inputArea.value); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } outputArea.value = new TextDecoder().decode(bytes); hideAlert(); } catch (e) { showAlert('Error decoding: Invalid Base64 string or character issue. ' + e.message, 'error'); outputArea.value = ''; } }; }, // --- Color Picker Tool --- colorPicker: (container) => { container.innerHTML = `

HEX:

RGB:

HSL:

`; const colorPickerInput = container.querySelector('#htmlColorPicker'); const colorPreviewDiv = container.querySelector('#colorPreview'); const hexValueSpan = container.querySelector('#hexValue'); const rgbValueSpan = container.querySelector('#rgbValue'); const hslValueSpan = container.querySelector('#hslValue'); const copyButtons = container.querySelectorAll('.copy-color-val'); let currentHex, currentRgb, currentHsl; function updateColorValues(hex) { currentHex = hex.toUpperCase(); colorPreviewDiv.style.backgroundColor = currentHex; hexValueSpan.textContent = currentHex; const rgb = hexToRgb(currentHex); currentRgb = `rgb(${rgb.r}, ${rgb.g}, ${rgb.b})`; rgbValueSpan.textContent = currentRgb; const hsl = rgbToHsl(rgb.r, rgb.g, rgb.b); currentHsl = `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`; hslValueSpan.textContent = currentHsl; } colorPickerInput.oninput = (e) => { updateColorValues(e.target.value); hideAlert(); }; copyButtons.forEach(btn => { btn.style.padding = "0.2em 0.5em"; // Smaller copy buttons btn.style.marginLeft = "5px"; btn.onclick = () => { let valueToCopy; const type = btn.dataset.type; if (type === 'hex') valueToCopy = currentHex; else if (type === 'rgb') valueToCopy = currentRgb; else if (type === 'hsl') valueToCopy = currentHsl; if (valueToCopy) { navigator.clipboard.writeText(valueToCopy) .then(() => showAlert(`${type.toUpperCase()} value copied!`, 'success')) .catch(() => showAlert('Failed to copy.', 'error')); } }; }); updateColorValues(colorPickerInput.value); // Initial value function hexToRgb(hex) { let r = 0, g = 0, b = 0; if (hex.length === 4) { r = parseInt(hex[1] + hex[1], 16); g = parseInt(hex[2] + hex[2], 16); b = parseInt(hex[3] + hex[3], 16); } else if (hex.length === 7) { r = parseInt(hex.substring(1, 3), 16); g = parseInt(hex.substring(3, 5), 16); b = parseInt(hex.substring(5, 7), 16); } return { r, g, b }; } function rgbToHsl(r, g, b) { r /= 255; g /= 255; b /= 255; const max = Math.max(r, g, b), min = Math.min(r, g, b); let h, s, l = (max + min) / 2; if (max === min) { h = s = 0; } else { const d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return { h: Math.round(h * 360), s: Math.round(s * 100), l: Math.round(l * 100) }; } }, // --- Text to Speech --- textToSpeech: (container) => { container.innerHTML = `
`; const textInput = container.querySelector('#ttsText'); const voiceSelect = container.querySelector('#ttsVoice'); const rateInput = container.querySelector('#ttsRate'); const pitchInput = container.querySelector('#ttsPitch'); const rateValSpan = container.querySelector('#ttsRateVal'); const pitchValSpan = container.querySelector('#ttsPitchVal'); const speakBtn = container.querySelector('#ttsSpeakBtn'); const pauseBtn = container.querySelector('#ttsPauseBtn'); const resumeBtn = container.querySelector('#ttsResumeBtn'); const stopBtn = container.querySelector('#ttsStopBtn'); const synth = window.speechSynthesis; if (!synth) { container.innerHTML = "

Sorry, your browser doesn't support Text to Speech.

"; return; } let voices = []; let currentUtterance = null; function populateVoiceList() { voices = synth.getVoices().sort((a,b) => a.name.localeCompare(b.name)); const selectedVoiceName = voiceSelect.value; voiceSelect.innerHTML = ''; voices.forEach(voice => { const option = document.createElement('option'); option.textContent = `${voice.name} (${voice.lang})`; option.value = voice.name; if (voice.default) option.selected = true; voiceSelect.appendChild(option); }); if (selectedVoiceName) voiceSelect.value = selectedVoiceName; // Retain selection } populateVoiceList(); if (synth.onvoiceschanged !== undefined) { synth.onvoiceschanged = populateVoiceList; } rateInput.oninput = () => rateValSpan.textContent = rateInput.value; pitchInput.oninput = () => pitchValSpan.textContent = pitchInput.value; speakBtn.onclick = () => { if (synth.speaking) { // If speaking, stop current and start new synth.cancel(); } if (textInput.value.trim() !== '') { hideAlert(); currentUtterance = new SpeechSynthesisUtterance(textInput.value.trim()); const selectedVoice = voices.find(voice => voice.name === voiceSelect.value); if (selectedVoice) currentUtterance.voice = selectedVoice; currentUtterance.pitch = parseFloat(pitchInput.value); currentUtterance.rate = parseFloat(rateInput.value); currentUtterance.onstart = () => { speakBtn.disabled = true; pauseBtn.disabled = false; resumeBtn.disabled = true; stopBtn.disabled = false; } currentUtterance.onend = () => { speakBtn.disabled = false; pauseBtn.disabled = true; resumeBtn.disabled = true; stopBtn.disabled = true; currentUtterance = null; }; currentUtterance.onerror = (e) => { showAlert(`Error during speech: ${e.error}`, 'error'); speakBtn.disabled = false; pauseBtn.disabled = true; resumeBtn.disabled = true; stopBtn.disabled = true; currentUtterance = null; }; synth.speak(currentUtterance); } else { showAlert('Please enter some text to speak.', 'error'); } }; pauseBtn.onclick = () => { if(synth.speaking && !synth.paused) { synth.pause(); pauseBtn.disabled = true; resumeBtn.disabled = false; } }; resumeBtn.onclick = () => { if(synth.paused) { synth.resume(); pauseBtn.disabled = false; resumeBtn.disabled = true; } }; stopBtn.onclick = () => { if(synth.speaking || synth.paused) { synth.cancel(); // This also triggers onend for the utterance } speakBtn.disabled = false; pauseBtn.disabled = true; resumeBtn.disabled = true; stopBtn.disabled = true; currentUtterance = null; }; // Initial button states speakBtn.disabled = false; pauseBtn.disabled = true; resumeBtn.disabled = true; stopBtn.disabled = true; window.currentToolCleanup = () => { if (synth && (synth.speaking || synth.paused)) { synth.cancel(); } }; }, // --- Speech to Text --- speechToText: (container) => { container.innerHTML = `

Click "Start Listening" and speak into your microphone. Allow microphone access when prompted.

`; const startBtn = container.querySelector('#sttStartBtn'); const stopBtn = container.querySelector('#sttStopBtn'); const outputArea = container.querySelector('#sttOutput'); const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; if (!SpeechRecognition) { container.innerHTML = '

Speech Recognition API is not supported in your browser.

'; return; } const recognition = new SpeechRecognition(); recognition.continuous = true; recognition.interimResults = true; recognition.lang = navigator.language || 'en-US'; // Use browser's language let finalTranscript = ''; recognition.onstart = () => { startBtn.disabled = true; stopBtn.disabled = false; showAlert('Listening... Speak clearly.', 'info'); }; recognition.onend = () => { startBtn.disabled = false; stopBtn.disabled = true; if (outputArea.value.trim() === '') hideAlert(); // Keep "Listening" if no final output yet else if (finalTranscript.trim() !== '') showAlert('Stopped listening.', 'success'); else showAlert('Stopped. No speech clearly recognized.', 'info'); }; recognition.onerror = (event) => { let errorMessage = `Speech recognition error: ${event.error}`; if (event.error === 'no-speech') { errorMessage = 'No speech was detected. Try speaking louder or closer to the microphone.'; } else if (event.error === 'audio-capture') { errorMessage = 'Audio capture failed. Ensure your microphone is working and permitted.'; } else if (event.error === 'not-allowed') { errorMessage = 'Microphone access denied. Please allow access in browser settings.'; } showAlert(errorMessage, 'error'); startBtn.disabled = false; stopBtn.disabled = true; }; recognition.onresult = (event) => { let interimTranscript = ''; for (let i = event.resultIndex; i < event.results.length; ++i) { if (event.results[i].isFinal) { finalTranscript += event.results[i][0].transcript + ' '; } else { interimTranscript += event.results[i][0].transcript; } } outputArea.value = finalTranscript + interimTranscript; if (interimTranscript) hideAlert(); // Hide general alerts if interim results are coming }; startBtn.onclick = () => { finalTranscript = ''; // Reset final transcript outputArea.value = ''; try { recognition.start(); } catch (e) { // Catch if already started if (e.name === 'InvalidStateError') { recognition.stop(); // Stop first, then it will be restartable on next click or via onend showAlert('Recognition was already active. Try again.', 'info'); } else { showAlert('Could not start recognition: ' + e.message, 'error'); } } }; stopBtn.onclick = () => recognition.stop(); window.currentToolCleanup = () => { if (recognition) { try { recognition.stop(); } catch(e){} } }; }, // --- JSON Formatter --- jsonFormatter: (container) => { container.innerHTML = `
`; const inputArea = container.querySelector('#jsonInput'); const outputArea = container.querySelector('#jsonOutput'); const formatBtn = container.querySelector('#formatJsonBtn'); const copyBtn = container.querySelector('#copyJsonBtn'); const spacesSelect = container.querySelector('#jsonSpaces'); formatBtn.onclick = () => { const jsonString = inputArea.value.trim(); if (!jsonString) { showAlert('Input is empty. Paste some JSON data.', 'info'); outputArea.value = ''; return; } try { const jsonObj = JSON.parse(jsonString); const spacesOption = spacesSelect.value; let indent; if (spacesOption === 'tab') { indent = '\t'; } else { indent = parseInt(spacesOption); } outputArea.value = JSON.stringify(jsonObj, null, indent); showAlert('JSON formatted successfully!', 'success'); } catch (e) { outputArea.value = 'Error: Invalid JSON\n\n' + e.message; showAlert('Invalid JSON: ' + e.message, 'error'); } }; copyBtn.onclick = () => { if (outputArea.value && !outputArea.value.startsWith('Error:')) { navigator.clipboard.writeText(outputArea.value) .then(() => showAlert('Formatted JSON copied!', 'success')) .catch(err => showAlert('Failed to copy.', 'error')); } else if (outputArea.value.startsWith('Error:')) { showAlert('Cannot copy error message. Please format valid JSON first.', 'info'); } else { showAlert('Nothing to copy. Format some JSON first.', 'info'); } }; }, // --- Unit Converter --- unitConverter: (container) => { const units = { length: { name: "Length", items: { meter: 1, kilometer: 1000, centimeter: 0.01, millimeter: 0.001, mile: 1609.34, yard: 0.9144, foot: 0.3048, inch: 0.0254, nautical_mile: 1852 } }, weight: { name: "Weight/Mass", items: { kilogram: 1, gram: 0.001, milligram: 0.000001, metric_ton: 1000, pound: 0.45359237, ounce: 0.0283495231, stone: 6.35029318 } }, temperature: { name: "Temperature", items: { celsius: 'celsius', fahrenheit: 'fahrenheit', kelvin: 'kelvin' } }, area: { name: "Area", items: { square_meter: 1, square_kilometer: 1000000, square_mile: 2589988.11, square_yard: 0.836127, square_foot: 0.092903, acre: 4046.86, hectare: 10000 } }, volume: { name: "Volume", items: { cubic_meter: 1, liter: 0.001, milliliter: 0.000001, US_gallon: 0.00378541, US_quart: 0.000946353, US_pint: 0.000473176, US_cup: 0.000236588, US_fluid_ounce: 0.0000295735, imperial_gallon: 0.00454609, imperial_quart: 0.00113652, imperial_pint: 0.000568261, imperial_fluid_ounce: 0.0000284131 } }, speed: { name: "Speed", items: { meters_per_second: 1, kilometers_per_hour: 0.277778, miles_per_hour: 0.44704, knot: 0.514444 } }, time: { name: "Time", items: { second: 1, minute: 60, hour: 3600, day: 86400, week: 604800, month_avg: 2629746, year_avg: 31556952 } }, // Add more categories like pressure, energy, power, data storage etc. }; container.innerHTML = `
Enter values and see result here
`; const categorySelect = container.querySelector('#ucCategory'); const fromUnitSelect = container.querySelector('#ucFromUnit'); const toUnitSelect = container.querySelector('#ucToUnit'); const valueInput = container.querySelector('#ucInputValue'); const resultDiv = container.querySelector('#ucResult'); function populateCategories() { for (const categoryKey in units) { const option = document.createElement('option'); option.value = categoryKey; option.textContent = units[categoryKey].name; categorySelect.appendChild(option); } } function populateUnitOptions(categoryKey) { const unitSet = units[categoryKey].items; fromUnitSelect.innerHTML = ''; toUnitSelect.innerHTML = ''; let count = 0; for (const unit in unitSet) { const optionText = unit.replace(/_/g, ' ').replace(/\b\w/g, l => l.toUpperCase()); // Prettify name const option1 = document.createElement('option'); option1.value = unit; option1.textContent = optionText; fromUnitSelect.appendChild(option1); const option2 = document.createElement('option'); option2.value = unit; option2.textContent = optionText; toUnitSelect.appendChild(option2); if (count === 1 && Object.keys(unitSet).length > 1) { // Select second item for "To" unit by default if available option2.selected = true; } count++; } if (Object.keys(unitSet).length === 1) { // If only one unit, select it for "To" as well toUnitSelect.selectedIndex = 0; } } function convertUnits() { const categoryKey = categorySelect.value; const fromUnit = fromUnitSelect.value; const toUnit = toUnitSelect.value; const inputValue = parseFloat(valueInput.value); if (isNaN(inputValue)) { resultDiv.textContent = 'Invalid input value.'; resultDiv.style.color = 'var(--accent-color)'; return; } hideAlert(); let result; const unitFactors = units[categoryKey].items; if (categoryKey === 'temperature') { if (fromUnit === toUnit) { result = inputValue; } else if (fromUnit === 'celsius') { if (toUnit === 'fahrenheit') result = (inputValue * 9/5) + 32; else if (toUnit === 'kelvin') result = inputValue + 273.15; } else if (fromUnit === 'fahrenheit') { if (toUnit === 'celsius') result = (inputValue - 32) * 5/9; else if (toUnit === 'kelvin') result = (inputValue - 32) * 5/9 + 273.15; } else if (fromUnit === 'kelvin') { if (toUnit === 'celsius') result = inputValue - 273.15; else if (toUnit === 'fahrenheit') result = (inputValue - 273.15) * 9/5 + 32; } } else { const baseValue = inputValue * unitFactors[fromUnit]; result = baseValue / unitFactors[toUnit]; } if (typeof result === 'undefined') { resultDiv.textContent = 'Conversion not supported or error.'; resultDiv.style.color = 'var(--accent-color)'; } else { const fromUnitText = fromUnitSelect.options[fromUnitSelect.selectedIndex].text; const toUnitText = toUnitSelect.options[toUnitSelect.selectedIndex].text; // Use more decimal places for precision, especially for small numbers const resultPrecision = Math.abs(result) > 0.0001 || result === 0 ? 4 : 8; resultDiv.textContent = `${inputValue} ${fromUnitText} = ${result.toFixed(resultPrecision)} ${toUnitText}`; resultDiv.style.color = 'var(--text-color)'; } } categorySelect.onchange = () => { populateUnitOptions(categorySelect.value); convertUnits(); // Convert immediately on category change }; fromUnitSelect.onchange = convertUnits; toUnitSelect.onchange = convertUnits; valueInput.oninput = convertUnits; populateCategories(); populateUnitOptions(categorySelect.value); // Initial population for default category convertUnits(); // Initial conversion }, // --- BMI Calculator --- bmiCalculator: (container) => { container.innerHTML = ` `; const weightInput = container.querySelector('#bmiWeight'); const heightInput = container.querySelector('#bmiHeight'); const calculateBtn = container.querySelector('#calculateBmiBtn'); const resultDiv = container.querySelector('#bmiResult'); calculateBtn.onclick = () => { const weight = parseFloat(weightInput.value); const heightCm = parseFloat(heightInput.value); if (isNaN(weight) || isNaN(heightCm) || weight <= 0 || heightCm <= 0) { showAlert('Please enter valid positive numbers for weight and height.', 'error'); resultDiv.style.display = 'none'; return; } const heightM = heightCm / 100; const bmi = weight / (heightM * heightM); let category = ''; let color = 'var(--text-color)'; if (bmi < 18.5) { category = 'Underweight'; color = '#3498db'; } // Blue else if (bmi < 24.9) { category = 'Normal weight'; color = '#2ecc71'; } // Green else if (bmi < 29.9) { category = 'Overweight'; color = '#f1c40f'; } // Yellow else if (bmi < 34.9) { category = 'Obesity Class I'; color = '#e67e22'; } // Orange else if (bmi < 39.9) { category = 'Obesity Class II'; color = '#e74c3c'; } // Red else { category = 'Obesity Class III (Severe)'; color = '#c0392b'; } // Darker Red resultDiv.innerHTML = `Your BMI: ${bmi.toFixed(2)}
Category: ${category}`; resultDiv.style.display = 'block'; hideAlert(); }; }, // --- Timer / Stopwatch --- timerStopwatch: (container) => { container.innerHTML = `

Timer




00:05:00
`; const tabButtons = container.querySelectorAll('.tab-button'); const tabContents = container.querySelectorAll('.tab-content'); tabButtons.forEach(button => { button.onclick = () => { tabButtons.forEach(btn => btn.classList.remove('active')); button.classList.add('active'); tabContents.forEach(content => content.style.display = 'none'); container.querySelector(`#${button.dataset.tab}`).style.display = 'block'; if (button.dataset.tab === 'timerTab') resetTimerState(false); else resetStopwatchState(false); }; }); // Timer Logic const timerHoursInput = container.querySelector('#timerHours'); const timerMinutesInput = container.querySelector('#timerMinutes'); const timerSecondsInput = container.querySelector('#timerSeconds'); const timerDisplay = container.querySelector('#timerDisplay'); const timerStartBtn = container.querySelector('#timerStart'); const timerPauseBtn = container.querySelector('#timerPause'); const timerResetBtn = container.querySelector('#timerReset'); let timerInterval; let timerTotalSeconds; let timerIsRunning = false; function updateTimerDisplayDOM() { const h = Math.floor(timerTotalSeconds / 3600); const m = Math.floor((timerTotalSeconds % 3600) / 60); const s = timerTotalSeconds % 60; timerDisplay.textContent = `${String(h).padStart(2, '0')}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`; } function setTimerFromInputs() { const h = parseInt(timerHoursInput.value) || 0; const m = parseInt(timerMinutesInput.value) || 0; const s = parseInt(timerSecondsInput.value) || 0; timerTotalSeconds = (h * 3600) + (m * 60) + s; updateTimerDisplayDOM(); } [timerHoursInput, timerMinutesInput, timerSecondsInput].forEach(input => { input.onchange = () => { if (!timerIsRunning) setTimerFromInputs(); }; input.onkeyup = () => { if (!timerIsRunning) setTimerFromInputs(); }; // For immediate update }); timerStartBtn.onclick = () => { if (timerIsRunning) return; // Already running if (timerTotalSeconds === undefined || timerTotalSeconds === 0) setTimerFromInputs(); // Set if not set from pause or initially 0 if (timerTotalSeconds <= 0) { showAlert('Set a duration greater than 0.', 'error'); return; } hideAlert(); timerIsRunning = true; timerStartBtn.disabled = true; timerPauseBtn.disabled = false; [timerHoursInput, timerMinutesInput, timerSecondsInput].forEach(inp => inp.disabled = true); timerInterval = setInterval(() => { if (timerTotalSeconds > 0) { timerTotalSeconds--; updateTimerDisplayDOM(); } else { clearInterval(timerInterval); timerIsRunning = false; timerDisplay.textContent = "Time's Up!"; showAlert("Timer finished!", "success"); timerStartBtn.disabled = false; timerPauseBtn.disabled = true; [timerHoursInput, timerMinutesInput, timerSecondsInput].forEach(inp => inp.disabled = false); try { new Audio('https://interactive-examples.mdn.mozilla.net/media/cc0-audio/t-rex-roar.mp3').play(); } catch(e){} // Example sound } }, 1000); }; timerPauseBtn.onclick = () => { clearInterval(timerInterval); timerIsRunning = false; timerStartBtn.disabled = false; timerPauseBtn.disabled = true; [timerHoursInput, timerMinutesInput, timerSecondsInput].forEach(inp => inp.disabled = false); // Re-enable inputs on pause }; function resetTimerState(showDefaultTime = true) { clearInterval(timerInterval); timerIsRunning = false; if (showDefaultTime) { timerHoursInput.value = '0'; timerMinutesInput.value = '5'; timerSecondsInput.value = '0'; } setTimerFromInputs(); timerStartBtn.disabled = false; timerPauseBtn.disabled = true; [timerHoursInput, timerMinutesInput, timerSecondsInput].forEach(inp => inp.disabled = false); hideAlert(); timerDisplay.textContent = "00:05:00"; // Reset visual if (showDefaultTime) setTimerFromInputs(); // Recalculate timerTotalSeconds } timerResetBtn.onclick = () => resetTimerState(true); // Stopwatch Logic const stopwatchDisplay = container.querySelector('#stopwatchDisplay'); const stopwatchStartBtn = container.querySelector('#stopwatchStart'); const stopwatchStopBtn = container.querySelector('#stopwatchStop'); const stopwatchResetBtn = container.querySelector('#stopwatchReset'); const stopwatchLapBtn = container.querySelector('#stopwatchLap'); const lapsList = container.querySelector('#lapsList'); let stopwatchInterval; let stopwatchStartTime; let stopwatchElapsedTime = 0; let lapNumber = 1; let stopwatchIsRunning = false; function formatStopwatchTime(ms) { const totalSeconds = Math.floor(ms / 1000); const minutes = Math.floor(totalSeconds / 60); const seconds = totalSeconds % 60; const milliseconds = Math.floor((ms % 1000)/10); return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}.${String(milliseconds).padStart(2, '0')}`; } stopwatchStartBtn.onclick = () => { if (stopwatchIsRunning) return; stopwatchIsRunning = true; stopwatchStartTime = Date.now() - stopwatchElapsedTime; stopwatchInterval = setInterval(() => { stopwatchElapsedTime = Date.now() - stopwatchStartTime; stopwatchDisplay.textContent = formatStopwatchTime(stopwatchElapsedTime); }, 10); stopwatchStartBtn.disabled = true; stopwatchStopBtn.disabled = false; stopwatchLapBtn.disabled = false; stopwatchResetBtn.disabled = false; // Enable reset when running or paused }; stopwatchStopBtn.onclick = () => { clearInterval(stopwatchInterval); stopwatchIsRunning = false; stopwatchStartBtn.disabled = false; stopwatchStopBtn.disabled = true; // Lap button can be active if paused with time stopwatchLapBtn.disabled = stopwatchElapsedTime === 0; }; function resetStopwatchState(fromTabSwitch = false) { clearInterval(stopwatchInterval); stopwatchIsRunning = false; stopwatchElapsedTime = 0; lapNumber = 1; stopwatchDisplay.textContent = formatStopwatchTime(0); if (!fromTabSwitch) lapsList.innerHTML = ''; // Clear laps only on explicit reset stopwatchStartBtn.disabled = false; stopwatchStopBtn.disabled = true; stopwatchLapBtn.disabled = true; stopwatchResetBtn.disabled = true; // Disabled when at 00:00 } stopwatchResetBtn.onclick = () => resetStopwatchState(false); stopwatchLapBtn.onclick = () => { if (stopwatchElapsedTime > 0) { const lapTime = stopwatchElapsedTime; const li = document.createElement('li'); li.textContent = `Lap ${lapNumber++}: ${formatStopwatchTime(lapTime)}`; lapsList.prepend(li); } }; resetTimerState(true); // Initial call for timer resetStopwatchState(false); // Initial call for stopwatch window.currentToolCleanup = () => { clearInterval(timerInterval); clearInterval(stopwatchInterval); }; } }; // Initial call for the default active tab (Timer) in Timer/Stopwatch if it's the first tool // This is more robustly handled by the tab switching logic now. // Ensure timer tab is default and its UI is correctly initialized const defaultTimerTabButton = document.querySelector('.tab-button[data-tab="timerTab"]'); if (defaultTimerTabButton) defaultTimerTabButton.click(); // Sample implementation for Case Converter function convertCase(text, caseType) { switch(caseType) { case 'upper': return text.toUpperCase(); case 'lower': return text.toLowerCase(); case 'title': return text.replace(/\w\S*/g, txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()); case 'sentence': return text.charAt(0).toUpperCase() + text.slice(1).toLowerCase(); default: return text; } } // Word Counter implementation function countWords(text) { return text.trim() === '' ? 0 : text.trim().split(/\s+/).length; } // PDF processing using PDF.js async function extractPDFText(file) { const pdf = await pdfjsLib.getDocument(file).promise; let text = ''; for (let i = 1; i <= pdf.numPages; i++) { const page = await pdf.getPage(i); const content = await page.getTextContent(); text += content.items.map(item => item.str).join(' '); } return text; } // Office document conversion using LibreOffice in Docker docker run --rm -v $(pwd):/convert -w /convert libreoffice \ --headless --convert-to pdf document.docx // Image compression using Sharp const compressImage = async (input, quality) => { return await sharp(input) .jpeg({ quality }) .png({ compressionLevel: 9 }) .toBuffer(); }; // Background removal using WASM port of REMBG const removeBackground = async (imageData) => { const model = await loadRembgWASM(); return model.removeBackground(imageData); }; // FFmpeg.wasm video conversion const convertVideo = async (file, format) => { const ffmpeg = createFFmpeg({ log: true }); await ffmpeg.load(); ffmpeg.FS('writeFile', 'input', file); await ffmpeg.run('-i', 'input', `output.${format}`); return ffmpeg.FS('readFile', `output.${format}`); }; // FFmpeg.wasm video conversion const convertVideo = async (file, format) => { const ffmpeg = createFFmpeg({ log: true }); await ffmpeg.load(); ffmpeg.FS('writeFile', 'input', file); await ffmpeg.run('-i', 'input', `output.${format}`); return ffmpeg.FS('readFile', `output.${format}`); }; // JSON formatter/validator function formatJSON(jsonString) { try { const obj = JSON.parse(jsonString); return { valid: true, formatted: JSON.stringify(obj, null, 2) }; } catch (e) { return { valid: false, error: e.message }; } } // JWT decoder function decodeJWT(token) { const [header, payload, signature] = token.split('.'); return { header: JSON.parse(atob(header)), payload: JSON.parse(atob(payload)), signature }; } // DNS lookup implementation async function dnsLookup(domain, recordType = 'A') { const response = await fetch(`https://cloudflare-dns.com/dns-query?name=${domain}&type=${recordType}`, { headers: { 'Accept': 'application/dns-json' } }); return response.json(); } // SSL checker async function checkSSL(domain) { const response = await fetch(`https://api.ssllabs.com/api/v3/analyze?host=${domain}`); return response.json(); } // Unit converter function convertUnits(value, fromUnit, toUnit) { const conversions = { length: { m: { km: 0.001, cm: 100, mm: 1000 }, km: { m: 1000, cm: 100000 } // ... other units }, weight: { kg: { g: 1000, lb: 2.20462 } // ... other units } }; // Find appropriate conversion path // Implementation depends on unit types } // Password generator function generatePassword(length = 12, options = {}) { const { uppercase = true, numbers = true, symbols = true } = options; let charset = 'abcdefghijklmnopqrstuvwxyz'; if (uppercase) charset += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; if (numbers) charset += '0123456789'; if (symbols) charset += '!@#$%^&*()'; let password = ''; for (let i = 0; i < length; i++) { password += charset.charAt(Math.floor(Math.random() * charset.length)); } return password; } import React from 'react'; import ToolContainer from './components/ToolContainer'; import { textTools, documentTools, imageTools, mediaTools, devTools, webTools, productivityTools } from './services'; function App() { const allTools = [ ...textTools, ...documentTools, ...imageTools, ...mediaTools, ...devTools, ...webTools, ...productivityTools ]; return (

Ultimate Toolbox

); } export default App; import React from 'react'; import ToolCard from './ToolCard'; const ToolContainer = ({ tools }) => { return (
{tools.map((tool, index) => ( ))}
); }; export default ToolContainer; export const textTools = [ { name: 'Case Converter', description: 'Convert text between different cases', component: ({ input }) => { const [output, setOutput] = React.useState(''); const convert = (type) => { switch(type) { case 'upper': return input.toUpperCase(); case 'lower': return input.toLowerCase(); case 'title': return input.replace(/\w\S*/g, txt => txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase()); default: return input; } }; return (