๐ณFermentation Calculator
Calculate ABV, gravity conversions, calories, and fermentation metrics for beer, wine, mead, and cider brewing with precision accuracy and AI assistance
๐ค What Is Fermentation Calculator?
Think of a brewing scientist in your pocket - that's the Fermentation Calculator! Calculate ABV, gravity readings, calories, and fermentation metrics for beer, wine, mead, and cider with precision. Get AI brewing assistance from ChatGPT and Claude for perfect batches every time!
๐บ Alcohol by Volume (ABV) Calculator
๐บ Enter your gravity readings to calculate ABV and fermentation metrics
โ๏ธ Gravity & Unit Converter
โ๏ธ Enter specific gravity to convert between Brix, Plato, and other units
๐ฅ Calorie & Carb Calculator
๐ฅ Enter gravity readings to calculate calories and carbohydrates
๐งช Yeast Pitch Rate Calculator
๐งช Enter batch details to calculate optimal yeast pitch rate
๐ Attenuation Calculator
๐ Enter gravity readings to calculate apparent and real attenuation
๐ฏ Try Sample Calculations
๐บ IPA Beer
OG: 1.065, FG: 1.012 โ 7.0% ABV
๐ท Red Wine
OG: 1.095, FG: 0.995 โ 13.3% ABV
๐ป Lager
OG: 1.048, FG: 1.008 โ 5.3% ABV
๐ฏ Mead
OG: 1.120, FG: 1.020 โ 13.4% ABV
๐ Cider
OG: 1.055, FG: 1.000 โ 7.2% ABV
๐ค Stout
OG: 1.072, FG: 1.018 โ 7.1% ABV
SG: ${data.correctedSG.toFixed(4)}
โ
Temperature corrected from ${data.temperature}ยฐF
Specific Gravity (Corrected)
${data.correctedSG.toFixed(4)}
Brix
${data.brix.toFixed(1)}ยฐBx
Plato
${data.plato.toFixed(1)}ยฐP
Oechsle
${data.oechsle.toFixed(0)}ยฐOe
Baumรฉ
${data.baume.toFixed(1)}ยฐBรฉ
Potential Alcohol
${data.potentialAlcohol.toFixed(1)}%
${data.totalCalories.toFixed(0)} calories
โ
Per ${data.servingSize} oz serving (${data.abv.toFixed(1)}% ABV)
Total Calories
${data.totalCalories.toFixed(0)}kcal
From Alcohol
${data.alcoholCalories.toFixed(0)}kcal
From Carbs
${data.carbCalories.toFixed(0)}kcal
Carbohydrates
${data.carbGrams.toFixed(1)}g
Alcohol Content
${data.abv.toFixed(1)}% ABV
Serving Size
${data.servingSize}oz
${data.pitchRate.toFixed(1)} M cells/mL/ยฐP
โ
Optimal pitch rate calculated for ${data.plato.toFixed(1)}ยฐP wort
Pitch Rate
${data.pitchRate.toFixed(1)}M/mL/ยฐP
Cells per mL
${data.cellsPerMl.toFixed(1)}M
Total Cells Needed
${(data.totalCells / 1000000000).toFixed(0)}B
Yeast Packets
${packetsNeeded.toFixed(1)}packs
Wort Gravity
${data.plato.toFixed(1)}ยฐP
Recommendation
${Math.ceil(packetsNeeded)}packs
${data.apparentAttenuation.toFixed(1)}% AA
โ
Fermentation efficiency analysis completed
Apparent Attenuation
${data.apparentAttenuation.toFixed(1)}%
Real Attenuation
${data.realAttenuation.toFixed(1)}%
Alcohol Content
${data.abv.toFixed(1)}% ABV
Real Extract
${data.realExtract.toFixed(1)}ยฐP
Original Gravity
${data.og.toFixed(3)}
Final Gravity
${data.fg.toFixed(3)}
${content.replace(/\n/g, '
')}`; } chatMessages.appendChild(messageDiv); chatMessages.scrollTop = chatMessages.scrollHeight; } // Gemini์ ๋ฉ์์ง ์ ์ก async function sendToGemini() { const input = document.getElementById('geminiInput'); const message = input.value.trim(); if (!message) return; // ์ฌ์ฉ์ ๋ฉ์์ง ์ถ๊ฐ addMessage('user', message); input.value = ''; // ๋ก๋ฉ ํ์ const loadingMsg = document.createElement('div'); loadingMsg.className = 'message assistant'; loadingMsg.innerHTML = 'โจ Gemini:
Thinking...'; loadingMsg.id = 'loading-message'; document.getElementById('chatMessages').appendChild(loadingMsg); try { const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${aiModalState.apiKey}`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ contents: [{ parts: [{ text: `Context: User is using the WIA Pin Code Fermentation Calculator tool for brewing calculations including ABV, gravity conversions, calories, yeast pitch rates, and attenuation for beer, wine, mead, and cider. Current tab: ${currentTab} User question: ${message} Please provide accurate brewing and fermentation advice. Include specific gravity calculations when relevant.` }] }], generationConfig: { temperature: 0.7, maxOutputTokens: 1000 } }) }); const data = await response.json(); // ๋ก๋ฉ ๋ฉ์์ง ์ ๊ฑฐ document.getElementById('loading-message').remove(); if (data.candidates && data.candidates[0] && data.candidates[0].content) { const reply = data.candidates[0].content.parts[0].text; addMessage('assistant', reply); } else { addMessage('assistant', 'Sorry, I could not generate a response. Please try again.'); } } catch (error) { // ๋ก๋ฉ ๋ฉ์์ง ์ ๊ฑฐ document.getElementById('loading-message')?.remove(); if (error.message.includes('API key')) { addMessage('error', 'Invalid API key. Please check your API key and try again.'); showAPIKeySetup(); } else { addMessage('error', 'Failed to connect to Gemini. Please check your internet connection and try again.'); } } } // ========== EVENT LISTENERS ========== // DOM Content Loaded document.addEventListener('DOMContentLoaded', function() { // Enter key support for inputs document.querySelectorAll('.input-field').forEach(input => { input.addEventListener('keypress', function(e) { if (e.key === 'Enter') { const activeSection = document.querySelector('.calc-section.active'); const button = activeSection.querySelector('.btn'); if (button) button.click(); } }); }); // Clear errors on input document.querySelectorAll('.input-field').forEach(input => { input.addEventListener('input', clearAllErrors); }); // Handle custom serving size toggle document.getElementById('servingSize').addEventListener('change', function() { const customGroup = document.getElementById('customServingGroup'); if (this.value === 'custom') { customGroup.style.display = 'block'; } else { customGroup.style.display = 'none'; } }); // AI ๋ฒํผ ์ด๋ฒคํธ document.getElementById('aiBtn').addEventListener('click', openAIModal); // ๋ชจ๋ฌ ์ธ๋ถ ํด๋ฆญ์ ๋ซ๊ธฐ document.getElementById('aiModal').addEventListener('click', function(e) { if (e.target === this) { closeAIModal(); } }); // ์ํฐ ํค ์ง์ ๋ฐ ESC ํค๋ก ๋ชจ๋ฌ ๋ซ๊ธฐ document.addEventListener('keydown', function(e) { if (e.key === 'Enter') { const geminiInput = document.getElementById('geminiInput'); if (document.activeElement === geminiInput) { sendToGemini(); } } // ESC ํค๋ก ๋ชจ๋ฌ ๋ซ๊ธฐ if (e.key === 'Escape') { closeAIModal(); } }); // ์ด๊ธฐ API ํค ์ํ ์ ๋ฐ์ดํธ updateAPIKeyStatus(); updateCurrentYear(); updateToolCount(); }); // Track WIA Pin Code clicks for analytics document.querySelectorAll('a[href*="wia"]').forEach(link => { link.addEventListener('click', function() { trackEvent('wia_link_click', { link: link.textContent }); }); }); // ========== DYNAMIC TOOL COUNT ========== // Update tool count dynamically async function updateToolCount() { try { const response = await fetch('/api/tool-count.php'); const data = await response.json(); // Update dynamic tools description document.querySelectorAll('.dynamic-tools-count').forEach(el => { el.textContent = `${data.count}+ free online tools in 211 languages. No signup, no fees, just tools that work.`; }); // Update "All X+ Tools" links document.querySelectorAll('.dynamic-count').forEach(el => { const prefix = el.getAttribute('data-text') || ''; const suffix = el.getAttribute('data-suffix') || ''; const icon = el.textContent.split(' ')[0] || ''; el.textContent = `${icon} ${prefix} ${data.count}+ ${suffix}`; }); } catch (error) { // Fallback: use current actual count from server const fallbackCount = 333; document.querySelectorAll('.dynamic-tools-count').forEach(el => { el.textContent = `${fallbackCount}+ free online tools in 211 languages. No signup, no fees, just tools that work.`; }); document.querySelectorAll('.dynamic-count').forEach(el => { const prefix = el.getAttribute('data-text') || ''; const suffix = el.getAttribute('data-suffix') || ''; const icon = el.textContent.split(' ')[0] || ''; el.textContent = `${icon} ${prefix} ${fallbackCount}+ ${suffix}`; }); console.log('Tool count API not available, using current count:', fallbackCount); } } // Update current year dynamically function updateCurrentYear() { const currentYear = new Date().getFullYear(); document.querySelectorAll('.current-year').forEach(el => { el.textContent = currentYear; }); } // ========== ANALYTICS ========== // Google Analytics window.dataLayer = window.dataLayer || []; function gtag(){dataLayer.push(arguments);} gtag('js', new Date()); gtag('config', 'G-XXXXXXXXX'); // Track page view trackEvent('page_view', { tool: TOOL_CONFIG.name, category: TOOL_CONFIG.category });