Files
InstaBase64/index.html
T
2026-02-24 12:30:24 +01:00

1101 lines
38 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>💌 Secret Message Versteckte Nachrichten</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;600;700&family=Sacramento&display=swap" rel="stylesheet">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
min-height: 100vh;
font-family: 'Quicksand', sans-serif;
background: linear-gradient(135deg, #fce4ec 0%, #f3e5f5 30%, #e8eaf6 60%, #fce4ec 100%);
background-size: 400% 400%;
animation: gradientShift 12s ease infinite;
color: #5d4037;
padding: 20px;
}
@keyframes gradientShift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* Floating hearts background */
.hearts-bg {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
pointer-events: none;
overflow: hidden;
z-index: 0;
}
.hearts-bg .heart {
position: absolute;
font-size: 20px;
opacity: 0.15;
animation: floatUp linear infinite;
}
@keyframes floatUp {
0% { transform: translateY(100vh) rotate(0deg) scale(1); opacity: 0; }
10% { opacity: 0.15; }
90% { opacity: 0.15; }
100% { transform: translateY(-10vh) rotate(360deg) scale(0.5); opacity: 0; }
}
.container {
max-width: 520px;
margin: 0 auto;
position: relative;
z-index: 1;
}
/* Header */
.header {
text-align: center;
margin-bottom: 30px;
}
.header .logo {
font-size: 48px;
margin-bottom: 6px;
}
.header h1 {
font-family: 'Sacramento', cursive;
font-size: 42px;
color: #e91e63;
text-shadow: 0 2px 8px rgba(233,30,99,0.15);
}
.header p {
font-size: 14px;
color: #ab8a8a;
margin-top: 4px;
}
/* Tabs */
.tabs {
display: flex;
gap: 8px;
margin-bottom: 20px;
}
.tab-btn {
flex: 1;
padding: 12px;
border: none;
border-radius: 16px;
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-size: 15px;
cursor: pointer;
transition: all 0.3s ease;
background: rgba(255,255,255,0.5);
color: #b0879b;
backdrop-filter: blur(8px);
}
.tab-btn.active {
background: linear-gradient(135deg, #f48fb1, #ce93d8);
color: #fff;
box-shadow: 0 4px 20px rgba(244,143,177,0.4);
transform: translateY(-2px);
}
.tab-btn:hover:not(.active) {
background: rgba(255,255,255,0.8);
}
/* Card */
.card {
background: rgba(255,255,255,0.7);
backdrop-filter: blur(16px);
border-radius: 24px;
padding: 28px 24px;
box-shadow: 0 8px 32px rgba(183,130,163,0.15);
border: 1px solid rgba(255,255,255,0.6);
margin-bottom: 20px;
transition: all 0.4s ease;
}
.card.hidden { display: none; }
.card-title {
display: flex;
align-items: center;
gap: 8px;
font-size: 18px;
font-weight: 700;
margin-bottom: 16px;
color: #7b5a6e;
}
.hint {
background: rgba(244,143,177,0.1);
border-radius: 12px;
padding: 12px 16px;
font-size: 13px;
color: #b0879b;
margin-bottom: 18px;
line-height: 1.5;
}
.hint strong { color: #e91e63; }
textarea {
width: 100%;
min-height: 110px;
border: 2px solid rgba(206,147,216,0.3);
border-radius: 16px;
padding: 16px;
font-family: 'Quicksand', sans-serif;
font-size: 15px;
color: #5d4037;
background: rgba(255,255,255,0.6);
resize: vertical;
transition: border-color 0.3s;
outline: none;
}
textarea:focus {
border-color: #f48fb1;
box-shadow: 0 0 0 3px rgba(244,143,177,0.15);
}
textarea::placeholder { color: #cbb3c0; }
.result-box {
width: 100%;
min-height: 80px;
background: linear-gradient(135deg, rgba(252,228,236,0.5), rgba(243,229,245,0.5));
border: 2px dashed rgba(206,147,216,0.4);
border-radius: 16px;
padding: 16px;
margin-top: 14px;
font-family: 'Quicksand', sans-serif;
font-size: 14px;
color: #7b5a6e;
word-break: break-all;
line-height: 1.6;
position: relative;
}
.result-box.empty {
display: flex;
align-items: center;
justify-content: center;
color: #cbb3c0;
font-style: italic;
}
.label {
font-size: 13px;
font-weight: 600;
color: #b0879b;
margin-bottom: 8px;
margin-top: 14px;
}
/* Buttons */
.btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 12px 22px;
border: none;
border-radius: 14px;
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-size: 14px;
cursor: pointer;
transition: all 0.3s ease;
}
.btn:active { transform: scale(0.96); }
.btn-primary {
background: linear-gradient(135deg, #f48fb1, #ce93d8);
color: #fff;
box-shadow: 0 4px 16px rgba(244,143,177,0.35);
}
.btn-primary:hover {
box-shadow: 0 6px 24px rgba(244,143,177,0.5);
transform: translateY(-2px);
}
.btn-secondary {
background: rgba(255,255,255,0.7);
color: #b0879b;
border: 2px solid rgba(206,147,216,0.3);
}
.btn-secondary:hover {
background: #fff;
border-color: #f48fb1;
color: #e91e63;
}
.btn-group {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-top: 16px;
}
/* Share buttons */
.share-section {
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid rgba(206,147,216,0.2);
}
.share-title {
font-size: 14px;
font-weight: 700;
color: #b0879b;
margin-bottom: 12px;
}
.share-btns {
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.btn-whatsapp {
background: linear-gradient(135deg, #66bb6a, #43a047);
color: #fff;
box-shadow: 0 4px 16px rgba(102,187,106,0.3);
}
.btn-whatsapp:hover {
box-shadow: 0 6px 24px rgba(102,187,106,0.5);
transform: translateY(-2px);
}
.btn-insta {
background: linear-gradient(135deg, #f58529, #dd2a7b, #8134af);
color: #fff;
box-shadow: 0 4px 16px rgba(221,42,123,0.3);
}
.btn-insta:hover {
box-shadow: 0 6px 24px rgba(221,42,123,0.5);
transform: translateY(-2px);
}
.btn-download {
background: linear-gradient(135deg, #7986cb, #5c6bc0);
color: #fff;
box-shadow: 0 4px 16px rgba(121,134,203,0.3);
}
.btn-download:hover {
box-shadow: 0 6px 24px rgba(121,134,203,0.5);
transform: translateY(-2px);
}
/* Image Preview */
.image-preview-section {
margin-top: 20px;
}
.image-preview-container {
border-radius: 16px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(183,130,163,0.2);
position: relative;
}
.image-preview-container canvas {
width: 100%;
display: block;
border-radius: 16px;
}
/* Style selector */
.style-selector {
display: flex;
gap: 8px;
margin-top: 14px;
flex-wrap: wrap;
}
.style-option {
width: 36px;
height: 36px;
border-radius: 50%;
border: 3px solid transparent;
cursor: pointer;
transition: all 0.3s;
}
.style-option:hover, .style-option.active {
border-color: #e91e63;
transform: scale(1.15);
box-shadow: 0 2px 12px rgba(233,30,99,0.3);
}
.style-option.s1 { background: linear-gradient(135deg, #fce4ec, #f8bbd0); }
.style-option.s2 { background: linear-gradient(135deg, #e8eaf6, #c5cae9); }
.style-option.s3 { background: linear-gradient(135deg, #e0f2f1, #b2dfdb); }
.style-option.s4 { background: linear-gradient(135deg, #fff8e1, #ffe082); }
.style-option.s5 { background: linear-gradient(135deg, #212121, #424242); }
/* Decode Reveal Animation */
.result-box.revealing {
background: linear-gradient(135deg, rgba(252,228,236,0.7), rgba(243,229,245,0.7));
border-color: #f48fb1;
border-style: solid;
animation: revealGlow 1.5s ease-in-out;
}
@keyframes revealGlow {
0% { box-shadow: 0 0 0 0 rgba(244,143,177,0); }
30% { box-shadow: 0 0 30px 8px rgba(244,143,177,0.4); }
60% { box-shadow: 0 0 20px 4px rgba(206,147,216,0.3); }
100% { box-shadow: 0 0 0 0 rgba(244,143,177,0); }
}
.result-box .reveal-char {
display: inline;
opacity: 0;
animation: charReveal 0.3s ease forwards;
}
@keyframes charReveal {
0% { opacity: 0; transform: translateY(8px) scale(0.7); filter: blur(4px); }
60% { opacity: 1; transform: translateY(-2px) scale(1.05); filter: blur(0); }
100% { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
}
.reveal-cursor {
display: inline-block;
width: 2px;
height: 1.1em;
background: #e91e63;
margin-left: 2px;
vertical-align: text-bottom;
animation: cursorBlink 0.6s step-end infinite;
}
@keyframes cursorBlink {
50% { opacity: 0; }
}
.reveal-emoji-burst {
position: absolute;
top: 50%;
left: 50%;
font-size: 28px;
pointer-events: none;
animation: emojiBurst 1s ease-out forwards;
z-index: 5;
}
@keyframes emojiBurst {
0% { transform: translate(-50%, -50%) scale(0) rotate(0deg); opacity: 1; }
50% { opacity: 1; }
100% { transform: translate(var(--tx), var(--ty)) scale(1.2) rotate(var(--rot)); opacity: 0; }
}
/* Confetti Canvas */
#confettiCanvas {
position: fixed;
top: 0; left: 0;
width: 100%; height: 100%;
pointer-events: none;
z-index: 999;
}
/* Toast */
.toast {
position: fixed;
bottom: 30px;
left: 50%;
transform: translateX(-50%) translateY(80px);
background: linear-gradient(135deg, #f48fb1, #ce93d8);
color: #fff;
padding: 14px 28px;
border-radius: 16px;
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-size: 14px;
box-shadow: 0 8px 32px rgba(244,143,177,0.4);
z-index: 1000;
transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.27, 1.55);
pointer-events: none;
}
.toast.show {
transform: translateX(-50%) translateY(0);
}
/* Language Toggle */
.lang-toggle {
position: fixed;
top: 16px;
right: 16px;
z-index: 100;
display: flex;
background: rgba(255,255,255,0.6);
backdrop-filter: blur(12px);
border-radius: 12px;
overflow: hidden;
border: 2px solid rgba(206,147,216,0.25);
box-shadow: 0 4px 16px rgba(183,130,163,0.12);
}
.lang-btn {
padding: 8px 14px;
border: none;
background: transparent;
font-family: 'Quicksand', sans-serif;
font-weight: 700;
font-size: 13px;
cursor: pointer;
color: #b0879b;
transition: all 0.3s;
}
.lang-btn.active {
background: linear-gradient(135deg, #f48fb1, #ce93d8);
color: #fff;
}
.lang-btn:hover:not(.active) {
background: rgba(244,143,177,0.12);
}
/* Footer */
.footer {
text-align: center;
margin-top: 30px;
font-size: 13px;
color: #cbb3c0;
}
.footer .made-by {
display: inline-block;
margin-top: 6px;
padding: 6px 18px;
background: linear-gradient(135deg, rgba(244,143,177,0.2), rgba(206,147,216,0.2));
border-radius: 20px;
font-weight: 700;
font-size: 14px;
color: #e91e63;
letter-spacing: 0.5px;
border: 1.5px solid rgba(233,30,99,0.15);
text-shadow: 0 1px 4px rgba(233,30,99,0.1);
}
/* Responsive */
@media (max-width: 480px) {
.header h1 { font-size: 34px; }
.card { padding: 20px 16px; }
.btn { padding: 10px 16px; font-size: 13px; }
.share-btns { flex-direction: column; }
.share-btns .btn { justify-content: center; }
}
</style>
</head>
<body>
<!-- Floating hearts -->
<div class="hearts-bg" id="heartsBg"></div>
<!-- Language Toggle -->
<div class="lang-toggle">
<button class="lang-btn active" onclick="setLang('de')">🇩🇪 DE</button>
<button class="lang-btn" onclick="setLang('en')">🇬🇧 EN</button>
</div>
<div class="container">
<!-- Header -->
<div class="header">
<div class="logo">💌</div>
<h1>Secret Message</h1>
<p data-i18n="subtitle">Verstecke deine Nachrichten nur Eingeweihte können sie lesen 🤫</p>
</div>
<!-- Tabs -->
<div class="tabs">
<button class="tab-btn active" onclick="switchTab('encode')" data-i18n="tabEncode">🔒 Verschlüsseln</button>
<button class="tab-btn" onclick="switchTab('decode')" data-i18n="tabDecode">🔓 Entschlüsseln</button>
</div>
<!-- ENCODE -->
<div class="card" id="encodeCard">
<div class="card-title" data-i18n="encodeTitle">✨ Geheime Nachricht erstellen</div>
<div class="hint" data-i18n-html="encodeHint">
Schreibe deine geheime Nachricht z.B. <strong>"Ich liebe dich 💕"</strong> und verschlüssele sie!
Teile den Code in deinem Insta-Status und nur wer weiß, wie man entschlüsselt, kann sie lesen 🤭
</div>
<div class="label" data-i18n="encodeLabel">Deine geheime Nachricht:</div>
<textarea id="encodeInput" data-i18n-placeholder="encodePlaceholder" placeholder="Schreibe hier deine geheime Nachricht… 💭"></textarea>
<div class="btn-group">
<button class="btn btn-primary" onclick="encodeMessage()" data-i18n="btnEncode">🔒 Verschlüsseln</button>
<button class="btn btn-secondary" onclick="clearEncode()" data-i18n="btnDelete">🗑️ Löschen</button>
</div>
<div class="label" data-i18n="encodeResultLabel">Verschlüsselter Code:</div>
<div class="result-box empty" id="encodeResult" data-i18n="encodeResultEmpty">Hier erscheint dein geheimer Code ✨</div>
<div class="btn-group" id="encodeBtns" style="display:none;">
<button class="btn btn-secondary" onclick="copyResult()" data-i18n="btnCopy">📋 Kopieren</button>
</div>
<!-- Image Generator -->
<div class="image-preview-section" id="imageSection" style="display:none;">
<div class="label" data-i18n="styleLabel">🎨 Bild-Stil wählen:</div>
<div class="style-selector">
<div class="style-option s1 active" onclick="selectStyle(0)" title="Rosa Traum"></div>
<div class="style-option s2" onclick="selectStyle(1)" title="Lavendel"></div>
<div class="style-option s3" onclick="selectStyle(2)" title="Minze"></div>
<div class="style-option s4" onclick="selectStyle(3)" title="Sonnenschein"></div>
<div class="style-option s5" onclick="selectStyle(4)" title="Dunkel"></div>
</div>
<div class="label" data-i18n="previewLabel">Vorschau:</div>
<div class="image-preview-container">
<canvas id="previewCanvas" width="1080" height="1080"></canvas>
</div>
<div class="share-section">
<div class="share-title" data-i18n="shareTitle">📤 Teilen & Herunterladen:</div>
<div class="share-btns">
<button class="btn btn-download" onclick="downloadImage()" data-i18n="btnDownload">📥 Bild speichern</button>
<button class="btn btn-whatsapp" onclick="shareWhatsApp()" data-i18n="btnWhatsApp">💬 WhatsApp</button>
<button class="btn btn-insta" onclick="shareInstagram()" data-i18n="btnInsta">📸 Instagram</button>
</div>
</div>
</div>
</div>
<!-- DECODE -->
<div class="card hidden" id="decodeCard">
<div class="card-title" data-i18n="decodeTitle">🔍 Geheime Nachricht entschlüsseln</div>
<div class="hint" data-i18n-html="decodeHint">
Hat dir jemand einen geheimen Code geschickt? 🤔<br>
Füge ihn hier ein und finde heraus, was die Nachricht verrät! 💕
</div>
<div class="label" data-i18n="decodeLabel">Verschlüsselter Code:</div>
<textarea id="decodeInput" data-i18n-placeholder="decodePlaceholder" placeholder="Füge hier den geheimen Code ein… 🔑"></textarea>
<div class="btn-group">
<button class="btn btn-primary" onclick="decodeMessage()" data-i18n="btnDecode">🔓 Entschlüsseln</button>
<button class="btn btn-secondary" onclick="clearDecode()" data-i18n="btnDelete">🗑️ Löschen</button>
</div>
<div class="label" data-i18n="decodeResultLabel">Die geheime Nachricht:</div>
<div class="result-box empty" id="decodeResult" data-i18n="decodeResultEmpty">Hier erscheint die entschlüsselte Nachricht 💌</div>
</div>
<!-- Footer -->
<div class="footer">
<span data-i18n="footerText">Sende geheime Nachrichten an deine Liebsten 💕</span><br>
<span class="made-by">Made by Mandy 🏳️‍⚧️</span>
</div>
</div>
<!-- Confetti -->
<canvas id="confettiCanvas"></canvas>
<!-- Toast -->
<div class="toast" id="toast"></div>
<script>
// ─── State ──────────────────────────────────────────────
let currentStyle = 0;
let encodedText = '';
let lang = 'de';
// ─── i18n ───────────────────────────────────────────────
const i18n = {
de: {
subtitle: 'Verstecke deine Nachrichten nur Eingeweihte können sie lesen 🤫',
tabEncode: '🔒 Verschlüsseln',
tabDecode: '🔓 Entschlüsseln',
encodeTitle: '✨ Geheime Nachricht erstellen',
encodeHint: 'Schreibe deine geheime Nachricht z.B. <strong>"Ich liebe dich 💕"</strong> und verschlüssele sie! Teile den Code in deinem Insta-Status und nur wer weiß, wie man entschlüsselt, kann sie lesen 🤭',
encodeLabel: 'Deine geheime Nachricht:',
encodePlaceholder: 'Schreibe hier deine geheime Nachricht… 💭',
btnEncode: '🔒 Verschlüsseln',
btnDelete: '🗑️ Löschen',
encodeResultLabel: 'Verschlüsselter Code:',
encodeResultEmpty: 'Hier erscheint dein geheimer Code ✨',
btnCopy: '📋 Kopieren',
styleLabel: '🎨 Bild-Stil wählen:',
previewLabel: 'Vorschau:',
shareTitle: '📤 Teilen & Herunterladen:',
btnDownload: '📥 Bild speichern',
btnWhatsApp: '💬 WhatsApp',
btnInsta: '📸 Instagram',
decodeTitle: '🔍 Geheime Nachricht entschlüsseln',
decodeHint: 'Hat dir jemand einen geheimen Code geschickt? 🤔<br>Füge ihn hier ein und finde heraus, was die Nachricht verrät! 💕',
decodeLabel: 'Verschlüsselter Code:',
decodePlaceholder: 'Füge hier den geheimen Code ein… 🔑',
btnDecode: '🔓 Entschlüsseln',
decodeResultLabel: 'Die geheime Nachricht:',
decodeResultEmpty: 'Hier erscheint die entschlüsselte Nachricht 💌',
footerText: 'Sende geheime Nachrichten an deine Liebsten 💕',
toastWriteFirst: '✏️ Schreibe zuerst eine Nachricht!',
toastEncoded: '🔒 Nachricht verschlüsselt!',
toastPasteFirst: '📋 Füge zuerst einen Code ein!',
toastDecoded: '💌 Geheime Nachricht entdeckt!',
toastInvalid: '❌ Ungültiger Code prüfe die Eingabe!',
toastCopied: '📋 Code kopiert!',
toastSaved: '📥 Bild gespeichert!',
toastInstaFallback: '📸 Bild gespeichert teile es in deiner Insta-Story!',
canvasTitle: 'Geheime Nachricht',
canvasSubtitle: 'Kannst du sie entschlüsseln?',
canvasDecodeHint: '🔓 Entschlüssele mit Base64-Decoder',
whatsAppText: '🤫 Ich habe eine geheime Nachricht für dich!\n\n🔒 Code: {code}\n\n🔓 Entschlüssele sie mit einem Base64-Decoder! 💌',
},
en: {
subtitle: 'Hide your messages only insiders can read them 🤫',
tabEncode: '🔒 Encrypt',
tabDecode: '🔓 Decrypt',
encodeTitle: '✨ Create Secret Message',
encodeHint: 'Write your secret message e.g. <strong>"I love you 💕"</strong> and encrypt it! Share the code in your Insta story and only those who know how to decrypt can read it 🤭',
encodeLabel: 'Your secret message:',
encodePlaceholder: 'Write your secret message here… 💭',
btnEncode: '🔒 Encrypt',
btnDelete: '🗑️ Clear',
encodeResultLabel: 'Encrypted code:',
encodeResultEmpty: 'Your secret code will appear here ✨',
btnCopy: '📋 Copy',
styleLabel: '🎨 Choose image style:',
previewLabel: 'Preview:',
shareTitle: '📤 Share & Download:',
btnDownload: '📥 Save image',
btnWhatsApp: '💬 WhatsApp',
btnInsta: '📸 Instagram',
decodeTitle: '🔍 Decrypt Secret Message',
decodeHint: 'Did someone send you a secret code? 🤔<br>Paste it here and find out what the message says! 💕',
decodeLabel: 'Encrypted code:',
decodePlaceholder: 'Paste the secret code here… 🔑',
btnDecode: '🔓 Decrypt',
decodeResultLabel: 'The secret message:',
decodeResultEmpty: 'The decrypted message will appear here 💌',
footerText: 'Send secret messages to your loved ones 💕',
toastWriteFirst: '✏️ Write a message first!',
toastEncoded: '🔒 Message encrypted!',
toastPasteFirst: '📋 Paste a code first!',
toastDecoded: '💌 Secret message revealed!',
toastInvalid: '❌ Invalid code check your input!',
toastCopied: '📋 Code copied!',
toastSaved: '📥 Image saved!',
toastInstaFallback: '📸 Image saved share it in your Insta story!',
canvasTitle: 'Secret Message',
canvasSubtitle: 'Can you decrypt it?',
canvasDecodeHint: '🔓 Decrypt with a Base64 decoder',
whatsAppText: '🤫 I have a secret message for you!\n\n🔒 Code: {code}\n\n🔓 Decrypt it with a Base64 decoder! 💌',
}
};
function t(key) { return i18n[lang][key] || key; }
function setLang(l) {
lang = l;
document.querySelectorAll('.lang-btn').forEach(b => b.classList.remove('active'));
document.querySelector(`.lang-btn:${l === 'de' ? 'first' : 'last'}-child`).classList.add('active');
// Update text content
document.querySelectorAll('[data-i18n]').forEach(el => {
el.textContent = t(el.dataset.i18n);
});
// Update innerHTML (for hints with <strong>)
document.querySelectorAll('[data-i18n-html]').forEach(el => {
el.innerHTML = t(el.dataset.i18nHtml);
});
// Update placeholders
document.querySelectorAll('[data-i18n-placeholder]').forEach(el => {
el.placeholder = t(el.dataset.i18nPlaceholder);
});
// Re-render canvas if visible
if (encodedText) renderPreview();
}
const styles = [
{ bg1: '#fce4ec', bg2: '#f8bbd0', accent: '#e91e63', text: '#880e4f', label: '#c2185d', emoji: '💕' },
{ bg1: '#e8eaf6', bg2: '#c5cae9', accent: '#5c6bc0', text: '#283593', label: '#3949ab', emoji: '💜' },
{ bg1: '#e0f2f1', bg2: '#b2dfdb', accent: '#26a69a', text: '#00695c', label: '#00897b', emoji: '🌿' },
{ bg1: '#fff8e1', bg2: '#ffe082', accent: '#ffa000', text: '#e65100', label: '#f57c00', emoji: '☀️' },
{ bg1: '#212121', bg2: '#424242', accent: '#f48fb1', text: '#fce4ec', label: '#f8bbd0', emoji: '🖤' },
];
// ─── Tabs ───────────────────────────────────────────────
function switchTab(tab) {
const btns = document.querySelectorAll('.tab-btn');
btns.forEach(b => b.classList.remove('active'));
if (tab === 'encode') {
btns[0].classList.add('active');
document.getElementById('encodeCard').classList.remove('hidden');
document.getElementById('decodeCard').classList.add('hidden');
} else {
btns[1].classList.add('active');
document.getElementById('encodeCard').classList.add('hidden');
document.getElementById('decodeCard').classList.remove('hidden');
}
}
// ─── Encode ─────────────────────────────────────────────
function encodeMessage() {
const input = document.getElementById('encodeInput').value.trim();
if (!input) {
showToast(t('toastWriteFirst'));
return;
}
// UTF-8 safe base64 encode
encodedText = btoa(unescape(encodeURIComponent(input)));
const resultEl = document.getElementById('encodeResult');
resultEl.textContent = encodedText;
resultEl.classList.remove('empty');
document.getElementById('encodeBtns').style.display = 'flex';
document.getElementById('imageSection').style.display = 'block';
renderPreview();
showToast(t('toastEncoded'));
}
function clearEncode() {
document.getElementById('encodeInput').value = '';
const resultEl = document.getElementById('encodeResult');
resultEl.textContent = t('encodeResultEmpty');
resultEl.classList.add('empty');
document.getElementById('encodeBtns').style.display = 'none';
document.getElementById('imageSection').style.display = 'none';
encodedText = '';
}
// ─── Decode with Reveal Animation ────────────────────────
function decodeMessage() {
const input = document.getElementById('decodeInput').value.trim();
if (!input) {
showToast(t('toastPasteFirst'));
return;
}
try {
const decoded = decodeURIComponent(escape(atob(input)));
const resultEl = document.getElementById('decodeResult');
resultEl.classList.remove('empty');
resultEl.classList.add('revealing');
resultEl.innerHTML = '<span class="reveal-cursor"></span>';
// Typewriter letter-by-letter reveal
const chars = [...decoded];
const baseDelay = Math.max(20, Math.min(60, 1500 / chars.length)); // adaptive speed
let i = 0;
function typeNext() {
if (i >= chars.length) {
// Remove cursor when done
const cursor = resultEl.querySelector('.reveal-cursor');
if (cursor) cursor.remove();
// Remove glow class after animation
setTimeout(() => resultEl.classList.remove('revealing'), 500);
// Launch confetti & emoji burst!
launchConfetti();
spawnEmojiBurst(resultEl);
showToast(t('toastDecoded'));
return;
}
const span = document.createElement('span');
span.className = 'reveal-char';
span.style.animationDelay = '0ms';
const ch = chars[i];
if (ch === ' ') {
span.innerHTML = '&nbsp;';
} else if (ch === '\n') {
resultEl.insertBefore(document.createElement('br'), resultEl.querySelector('.reveal-cursor'));
i++;
typeNext();
return;
} else {
span.textContent = ch;
}
resultEl.insertBefore(span, resultEl.querySelector('.reveal-cursor'));
i++;
setTimeout(typeNext, baseDelay);
}
// Small initial pause for dramatic effect
setTimeout(typeNext, 300);
} catch (e) {
showToast(t('toastInvalid'));
}
}
// ─── Emoji Burst around result box ───────────────────────
function spawnEmojiBurst(container) {
const emojis = ['💕', '💖', '✨', '💌', '🦋', '🌸', '💗', '🥰', '💜'];
const rect = container.getBoundingClientRect();
for (let i = 0; i < 10; i++) {
const el = document.createElement('span');
el.className = 'reveal-emoji-burst';
el.textContent = emojis[Math.floor(Math.random() * emojis.length)];
const angle = (i / 10) * Math.PI * 2;
const dist = 60 + Math.random() * 80;
el.style.setProperty('--tx', `${Math.cos(angle) * dist}px`);
el.style.setProperty('--ty', `${Math.sin(angle) * dist - 40}px`);
el.style.setProperty('--rot', `${Math.random() * 360}deg`);
el.style.animationDelay = `${Math.random() * 0.3}s`;
el.style.position = 'absolute';
container.style.position = 'relative';
container.appendChild(el);
setTimeout(() => el.remove(), 1500);
}
}
// ─── Confetti ────────────────────────────────────────────
function launchConfetti() {
const canvas = document.getElementById('confettiCanvas');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const colors = ['#f48fb1','#ce93d8','#e91e63','#ff80ab','#ea80fc','#b388ff','#82b1ff','#fce4ec','#f8bbd0'];
const particles = [];
for (let i = 0; i < 120; i++) {
particles.push({
x: canvas.width / 2 + (Math.random() - 0.5) * 200,
y: canvas.height / 2,
vx: (Math.random() - 0.5) * 16,
vy: -Math.random() * 18 - 4,
w: 6 + Math.random() * 6,
h: 4 + Math.random() * 8,
color: colors[Math.floor(Math.random() * colors.length)],
rotation: Math.random() * 360,
rotSpeed: (Math.random() - 0.5) * 12,
gravity: 0.25 + Math.random() * 0.15,
opacity: 1,
shape: Math.random() > 0.5 ? 'rect' : 'circle',
});
}
let frame = 0;
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
let alive = false;
particles.forEach(p => {
p.vy += p.gravity;
p.x += p.vx;
p.y += p.vy;
p.vx *= 0.99;
p.rotation += p.rotSpeed;
if (frame > 40) p.opacity -= 0.015;
if (p.opacity > 0 && p.y < canvas.height + 20) {
alive = true;
ctx.save();
ctx.globalAlpha = Math.max(0, p.opacity);
ctx.translate(p.x, p.y);
ctx.rotate((p.rotation * Math.PI) / 180);
ctx.fillStyle = p.color;
if (p.shape === 'rect') {
ctx.fillRect(-p.w / 2, -p.h / 2, p.w, p.h);
} else {
ctx.beginPath();
ctx.arc(0, 0, p.w / 2, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
}
});
frame++;
if (alive) {
requestAnimationFrame(animate);
} else {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
}
animate();
}
function clearDecode() {
document.getElementById('decodeInput').value = '';
const resultEl = document.getElementById('decodeResult');
resultEl.textContent = t('decodeResultEmpty');
resultEl.classList.add('empty');
}
// ─── Copy ───────────────────────────────────────────────
function copyResult() {
if (!encodedText) return;
navigator.clipboard.writeText(encodedText).then(() => {
showToast(t('toastCopied'));
});
}
// ─── Image Generation (Canvas) ─────────────────────────
function selectStyle(idx) {
currentStyle = idx;
document.querySelectorAll('.style-option').forEach((el, i) => {
el.classList.toggle('active', i === idx);
});
renderPreview();
}
function renderPreview() {
const canvas = document.getElementById('previewCanvas');
const ctx = canvas.getContext('2d');
const s = styles[currentStyle];
const W = 1080, H = 1080;
// Background gradient
const grad = ctx.createLinearGradient(0, 0, W, H);
grad.addColorStop(0, s.bg1);
grad.addColorStop(1, s.bg2);
ctx.fillStyle = grad;
ctx.fillRect(0, 0, W, H);
// Decorative circles
ctx.globalAlpha = 0.07;
ctx.fillStyle = s.accent;
ctx.beginPath(); ctx.arc(150, 150, 200, 0, Math.PI * 2); ctx.fill();
ctx.beginPath(); ctx.arc(930, 900, 250, 0, Math.PI * 2); ctx.fill();
ctx.beginPath(); ctx.arc(850, 200, 120, 0, Math.PI * 2); ctx.fill();
ctx.globalAlpha = 1;
// Top emoji
ctx.font = '72px serif';
ctx.textAlign = 'center';
ctx.fillText('🤫', W / 2, 160);
// Title
ctx.font = 'bold 48px Quicksand, sans-serif';
ctx.fillStyle = s.accent;
ctx.fillText(t('canvasTitle'), W / 2, 250);
// Subtitle
ctx.font = '28px Quicksand, sans-serif';
ctx.fillStyle = s.label;
ctx.fillText(t('canvasSubtitle') + ' ' + s.emoji, W / 2, 310);
// Code box background
const boxX = 80, boxY = 380, boxW = W - 160, boxH = 340;
ctx.fillStyle = currentStyle === 4 ? 'rgba(255,255,255,0.08)' : 'rgba(255,255,255,0.5)';
roundRect(ctx, boxX, boxY, boxW, boxH, 24);
ctx.fill();
// Border
ctx.strokeStyle = s.accent + '40';
ctx.lineWidth = 3;
roundRect(ctx, boxX, boxY, boxW, boxH, 24);
ctx.stroke();
// Code text (word-wrap)
ctx.font = '26px Quicksand, sans-serif';
ctx.fillStyle = s.text;
ctx.textAlign = 'center';
wrapText(ctx, encodedText, W / 2, boxY + 60, boxW - 60, 38);
// Decode hint
ctx.font = '24px Quicksand, sans-serif';
ctx.fillStyle = s.label;
ctx.textAlign = 'center';
ctx.fillText(t('canvasDecodeHint'), W / 2, 800);
// Website / branding
ctx.font = 'bold 22px Quicksand, sans-serif';
ctx.fillStyle = s.accent;
ctx.fillText('💌 Secret Message', W / 2, 880);
// Bottom decorative dots
ctx.globalAlpha = 0.15;
ctx.fillStyle = s.accent;
for (let i = 0; i < 5; i++) {
ctx.beginPath();
ctx.arc(W / 2 - 80 + i * 40, 940, 6, 0, Math.PI * 2);
ctx.fill();
}
ctx.globalAlpha = 1;
}
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
}
function wrapText(ctx, text, x, y, maxWidth, lineHeight) {
if (!text) return;
const chars = text.split('');
let line = '';
let lineY = y;
for (let i = 0; i < chars.length; i++) {
const testLine = line + chars[i];
const metrics = ctx.measureText(testLine);
if (metrics.width > maxWidth && line.length > 0) {
ctx.fillText(line, x, lineY);
line = chars[i];
lineY += lineHeight;
} else {
line = testLine;
}
}
ctx.fillText(line, x, lineY);
}
// ─── Download Image ─────────────────────────────────────
function downloadImage() {
const canvas = document.getElementById('previewCanvas');
const link = document.createElement('a');
link.download = 'secret-message.png';
link.href = canvas.toDataURL('image/png');
link.click();
showToast(t('toastSaved'));
}
// ─── Share WhatsApp ─────────────────────────────────────
function shareWhatsApp() {
const text = t('whatsAppText').replace('{code}', encodedText);
const url = `https://wa.me/?text=${encodeURIComponent(text)}`;
window.open(url, '_blank');
}
// ─── Share Instagram ────────────────────────────────────
async function shareInstagram() {
const canvas = document.getElementById('previewCanvas');
// Try Web Share API first (works on mobile)
if (navigator.share && navigator.canShare) {
try {
const blob = await new Promise(res => canvas.toBlob(res, 'image/png'));
const file = new File([blob], 'secret-message.png', { type: 'image/png' });
if (navigator.canShare({ files: [file] })) {
await navigator.share({
title: '💌 Secret Message',
text: '🤫 Kannst du meine geheime Nachricht entschlüsseln?',
files: [file],
});
return;
}
} catch (e) {
// User cancelled or error fall through
}
}
// Fallback: download the image and show instructions
downloadImage();
showToast(t('toastInstaFallback'));
}
// ─── Toast ──────────────────────────────────────────────
function showToast(msg) {
const toast = document.getElementById('toast');
toast.textContent = msg;
toast.classList.add('show');
setTimeout(() => toast.classList.remove('show'), 2500);
}
// ─── Floating Hearts ────────────────────────────────────
function createHearts() {
const container = document.getElementById('heartsBg');
const emojis = ['💕', '💗', '💖', '✨', '🌸', '💌', '🦋'];
for (let i = 0; i < 18; i++) {
const heart = document.createElement('span');
heart.className = 'heart';
heart.textContent = emojis[Math.floor(Math.random() * emojis.length)];
heart.style.left = Math.random() * 100 + '%';
heart.style.fontSize = (14 + Math.random() * 18) + 'px';
heart.style.animationDuration = (8 + Math.random() * 14) + 's';
heart.style.animationDelay = (Math.random() * 10) + 's';
container.appendChild(heart);
}
}
createHearts();
</script>
</body>
</html>