This is a first attempt to create a custom fancy font generator. Enter some text and the code will use alternative Unicode letters.
This is a first attempt to create a custom fancy font generator. Enter some text and the code will use alternative Unicode letters. This quick tool also has a small „variation“ feature – try it out if you like a style. I also tried to mix some Runic symbols in the selection. This is all experimental. Enjoy the ONLINE DEMO or just take this code 🙂
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>ᏖᏬᏒᏰᎧᏩᏝᎥᎮ'Ꮥ ᏅᏬᎥᏟᏦ ᏩᏗᏁᏟᎩ ᏩᎧᏁᏖ ᎶᏋᏁᏋᏒᏗᏖᎧᏒ</title> <!-- Tailwind CSS CDN für einfaches Styling --> <script src="https://cdn.tailwindcss.com"></script> <!-- Inter Font von Google Fonts --> <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap" rel="stylesheet"> <style> body { font-family: 'Inter', sans-serif; background-color: #f0f4f8; /* Heller blaugrauer Hintergrund */ color: #334155; /* Dunklerer Text */ } /* Benutzerdefinierte Scrollleiste für den Ausgabebereich */ .output-scroll-area::-webkit-scrollbar { width: 8px; } .output-scroll-area::-webkit-scrollbar-track { background: #e2e8f0; border-radius: 10px; } .output-scroll-area::-webkit-scrollbar-thumb { background: #94a3b8; border-radius: 10px; } .output-scroll-area::-webkit-scrollbar-thumb:hover { background: #64748b; } /* Stil für die Nachrichtenbox */ .message-box { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background-color: #34d399; /* Grün für Erfolg */ color: white; padding: 12px 20px; border-radius: 8px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); z-index: 1000; opacity: 0; transition: opacity 0.3s ease-in-out; } .message-box.show { opacity: 1; } .vary-button { transition: all 0.2s ease-in-out; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); /* Leichter Schatten für weiße Buttons */ } .vary-button:hover { transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .vary-button:active { transform: translateY(0); box-shadow: none; } </style> </head> <body class="flex flex-col items-center justify-center min-h-screen py-8 px-4 sm:px-6 lg:px-8"> <div class="message-box" id="messageBox"></div> <div class="bg-white p-6 rounded-xl shadow-2xl w-full max-w-4xl space-y-6"> <div class="flex flex-col sm:flex-row gap-3"> <input type="text" id="inputText" placeholder="Geben Sie hier Ihren Text ein..." class="flex-grow p-3 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500 text-base shadow-sm" maxlength="100" > <button id="generateButton" class="px-5 py-2 bg-white text-gray-700 font-semibold rounded-lg shadow-md hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition duration-200 ease-in-out text-base" > Generieren </button> </div> <div id="variationsHeaderContainer" class="flex flex-col gap-2 mt-4 pt-2 hidden"> <h2 class="text-xl font-bold text-gray-800 text-center">Variationen</h2> </div> <div id="outputContainer" class="flex flex-col gap-4 mt-6 max-h-[60vh] overflow-y-auto pr-2 output-scroll-area"> <!-- Fancy Fonts werden hier angezeigt --> <p class="text-gray-500 text-center">Geben Sie etwas ein und klicken Sie auf 'Generieren', um die Magie zu sehen!</p> </div> </div> <script> // Hilfsfunktion zum Anzeigen von Nachrichten function showMessage(message, type = 'success') { const messageBox = document.getElementById('messageBox'); messageBox.textContent = message; messageBox.className = 'message-box show'; if (type === 'success') { messageBox.style.backgroundColor = '#34d399'; // Grün } else if (type === 'error') { messageBox.style.backgroundColor = '#ef4444'; // Rot } setTimeout(() => { messageBox.className = 'message-box'; }, 3000); } const FONT_TYPES = { CHAR_SUBSTITUTION: 'char_substitution' }; // Mappings für verschiedene Fancy Fonts (alle CHAR_SUBSTITUTION) const FONT_MAPS = [ // --- Benutzer-Beispiele zuerst --- { type: FONT_TYPES.CHAR_SUBSTITUTION, // Canadian Aboriginal Syllabics Lookalikes (ausgewählte, visuelle Übereinstimmung) map: { 'a': 'ᗩ', 'b': 'ᗷ', 'c': 'ᑢ', 'd': 'ᑐ', 'e': 'ᘿ', 'f': 'ᖬ', 'g': 'ᘜ', 'h': 'ᕼ', 'i': 'ᓰ', 'j': 'ᒍ', 'k': 'ᖽᐸ', 'l': 'ᒪ', 'm': 'ᗰ', 'n': 'ᘉ', 'o': 'ᓍ', 'p': 'ᕵ', 'q': 'ᑫ', 'r': 'ᖇ', 's': 'S', 't': 'ᖶ', 'u': 'ᑘ', 'v': 'ᐯ', 'w': 'ᗯ', 'x': '᙮', 'y': 'ᖻ', 'z': 'ᗣ', 'A': 'ᗩ', 'B': 'ᗷ', 'C': 'ᑢ', 'D': 'ᑐ', 'E': 'ᘿ', 'F': 'ᖬ', 'G': 'ᘜ', 'H': 'ᕼ', 'I': 'ᓰ', 'J': 'ᒍ', 'K': 'ᖽᐸ', 'L': 'ᒪ', 'M': 'ᗰ', 'N': 'ᘉ', 'O': 'ᓍ', 'P': 'ᕵ', 'Q': 'ᑫ', 'R': 'ᖇ', 'S': 'S', 'T': 'ᖶ', 'U': 'ᑘ', 'V': 'ᐯ', 'W': 'ᗯ', 'X': '᙮', 'Y': 'ᖻ', 'Z': 'ᗣ', ' ': ' ' } }, { type: FONT_TYPES.CHAR_SUBSTITUTION, // Mixed Script (Thai, Hebrew, Cyrillic, Armenian - รקคгкєг) map: { 'a': 'ค', 'b': '๒', 'c': 'ς', 'd': '๔', 'e': 'є', 'f': 'Ŧ', 'g': 'ﻮ', 'h': 'ђ', 'i': 'เ', 'j': 'ן', 'k': 'к', 'l': 'l', 'm': '๓', 'n': 'ภ', 'o': '๏', 'p': 'ק', 'q': 'ợ', 'r': 'г', 's': 'ร', 't': 'Շ', 'u': 'ย', 'v': 'ש', 'w': 'ฬ', 'x': 'א', 'y': 'ץ', 'z': 'չ', 'A': 'ค', 'B': '๒', 'C': 'ς', 'D': '๔', 'E': 'є', 'F': 'Ŧ', 'G': 'ﻮ', 'H': 'ђ', 'I': 'เ', 'J': 'ן', 'K': 'к', 'L': 'l', 'M': '๓', 'N': 'ภ', 'O': '๏', 'P': 'ק', 'Q': 'ợ', 'R': 'г', 'S': 'ร', 'T': 'Շ', 'U': 'ย', 'V': 'ש', 'W': 'ฬ', 'X': 'א', 'Y': 'ץ', 'Z': 'չ', ' ': ' ' } }, { type: FONT_TYPES.CHAR_SUBSTITUTION, // Cherokee Script (ᏕᎮᏗᏒᏦᏋᏒ) map: { 'a': 'Ꮧ', 'b': 'Ᏸ', 'c': 'Ꮯ', 'd': 'Ꮄ', 'e': 'Ꮛ', 'f': 'Ꮹ', 'g': 'Ꮆ', 'h': 'Ꮋ', 'i': 'Ꭵ', 'j': 'Ꮷ', 'k': 'Ꮶ', 'l': 'Ꮭ', 'm': 'Ꮇ', 'n': 'Ꮑ', 'o': 'Ꭷ', 'p': 'Ꭾ', 'q': 'Ꮕ', 'r': 'Ꮢ', 's': 'Ꮥ', 't': 'Ꮦ', 'u': 'Ꮼ', 'v': 'Ꮩ', 'w': 'Ꮹ', 'x': 'Ꮿ', 'y': 'Ꭹ', 'z': 'Ꮓ', 'A': 'Ꮧ', 'B': 'Ᏸ', 'C': 'Ꮯ', 'D': 'Ꮄ', 'E': 'Ꮛ', 'F': 'Ꮹ', 'G': 'Ꮆ', 'H': 'Ꮋ', 'I': 'Ꭵ', 'J': 'Ꮷ', 'K': 'Ꮶ', 'L': 'Ꮭ', 'M': 'Ꮇ', 'N': 'Ꮑ', 'O': 'Ꭷ', 'P': 'Ꭾ', 'Q': 'Ꮕ', 'R': 'Ꮢ', 'S': 'Ꮥ', 'T': 'Ꮦ', 'U': 'Ꮼ', 'V': 'Ꮩ', 'W': 'Ꮹ', 'X': 'Ꮿ', 'Y': 'Ꭹ', 'Z': 'Ꮓ', ' ': ' ' } }, { type: FONT_TYPES.CHAR_SUBSTITUTION, // Georgian Lookalikes (selektiert, visuelle Übereinstimmung) map: { 'a': 'Ⴀ', 'b': 'Ⴁ', 'c': 'Ⴍ', 'd': 'Ⴃ', 'e': 'Ⴄ', 'f': 'Ⴔ', 'g': 'Ⴂ', 'h': 'Ⴠ', 'i': 'Ⴈ', 'j': 'Ⴟ', 'k': 'Ⴉ', 'l': 'Ⴊ', 'm': 'Ⴋ', 'n': 'Ⴌ', 'o': 'Ⴍ', 'p': 'Ⴎ', 'q': 'Ⴢ', 'r': 'Ⴐ', 's': 'Ⴑ', 't': 'Ⴒ', 'u': 'Ⴓ', 'v': 'Ⴜ', 'w': 'Ⴗ', 'x': 'Ⴜ', 'y': 'Ⴡ', 'z': 'Ⴏ', 'A': 'Ⴀ', 'B': 'Ⴁ', 'C': 'Ⴍ', 'D': 'Ⴃ', 'E': 'Ⴄ', 'F': 'Ⴔ', 'G': 'Ⴂ', 'H': 'Ⴠ', 'I': 'Ⴈ', 'J': 'Ⴟ', 'K': 'Ⴉ', 'L': 'Ⴊ', 'M': 'Ⴋ', 'N': 'Ⴌ', 'O': 'Ⴍ', 'P': 'Ⴎ', 'Q': 'Ⴢ', 'R': 'Ⴐ', 'S': 'Ⴑ', 'T': 'Ⴒ', 'U': 'Ⴓ', 'V': 'Ⴜ', 'W': 'Ⴗ', 'X': 'Ⴜ', 'Y': 'Ⴡ', 'Z': 'Ⴏ', ' ': ' ' } }, { type: FONT_TYPES.CHAR_SUBSTITUTION, // Runic Lookalikes (selected characters from Elder Futhark) map: { 'a': 'ᚨ', 'b': 'ᛒ', 'c': 'ᚳ', 'd': 'ᛞ', 'e': 'ᛖ', 'f': 'ᚠ', 'g': 'ᚷ', 'h': 'ᚺ', 'i': 'ᛁ', 'j': 'ᛃ', 'k': 'ᚴ', 'l': 'ᛚ', 'm': 'ᛗ', 'n': 'ᚾ', 'o': 'ᛟ', 'p': 'ᛈ', 'q': 'ᚦ', 'r': 'ᚱ', 's': 'ᛋ', 't': 'ᛏ', 'u': 'ᚢ', 'v': 'ᚹ', 'w': 'ᚹ', 'x': 'ᛜ', 'y': 'ᚣ', 'z': 'ᛉ', 'A': 'ᚨ', 'B': 'ᛒ', 'C': 'ᚳ', 'D': 'ᛞ', 'E': 'ᛖ', 'F': 'ᚠ', 'G': 'ᚷ', 'H': 'ᚺ', 'I': 'ᛁ', 'J': 'ᛃ', 'K': 'ᚴ', 'L': 'ᛚ', 'M': 'ᛗ', 'N': 'ᚾ', 'O': 'ᛟ', 'P': 'ᛈ', 'Q': 'ᚦ', 'R': 'ᚱ', 'S': 'ᛋ', 'T': 'ᛏ', 'U': 'ᚢ', 'V': 'ᚹ', 'W': 'ᚹ', 'X': 'ᛜ', 'Y': 'ᚣ', 'Z': 'ᛉ', ' ': ' ' } } ]; // Funktion zum Konvertieren von Text basierend auf einer bestimmten Zuordnung function convertText(text, fontMap) { let convertedText = ''; const normalizedText = text.normalize('NFD'); for (let i = 0; i < normalizedText.length; i++) { const char = normalizedText[i]; // Stellen Sie sicher, dass keine kombinierenden Diakritika als Basiszeichen behandelt werden if (char.length > 1 && /[\u0300-\u036F]/.test(char)) { convertedText += char; continue; } const lowerChar = char.toLowerCase(); const upperChar = char.toUpperCase(); if (fontMap.map[char]) { convertedText += fontMap.map[char]; } else if (fontMap.map[lowerChar] && char === upperChar) { convertedText += fontMap.map[lowerChar].toUpperCase(); } else { convertedText += char; // Zeichen unverändert lassen, wenn nicht in der Map } } return convertedText.normalize('NFC'); } // Funktion zum Generieren von Variationen eines Zeichenersetzungs-Stils function generateCharSubstitutionVariations(originalText, count = 5) { const variations = []; const charSubMaps = FONT_MAPS.filter(f => f.type === FONT_TYPES.CHAR_SUBSTITUTION); for (let i = 0; i < count; i++) { let variedText = ''; for (let j = 0; j < originalText.length; j++) { const char = originalText[j]; if (char === ' ') { variedText += ' '; continue; } const randomMapIndex = Math.floor(Math.random() * charSubMaps.length); const selectedFontMap = charSubMaps[randomMapIndex]; variedText += convertText(char, selectedFontMap); } variations.push({ type: FONT_TYPES.CHAR_SUBSTITUTION, map: {}, convertedText: variedText }); } return variations; } // Funktion zum Anzeigen der generierten Fancy Fonts und deren Buttons function displayFancyFonts(inputText, isVariationMode = false, originalFontDetails = null) { const outputContainer = document.getElementById('outputContainer'); const variationsHeader = document.getElementById('variationsHeaderContainer'); outputContainer.innerHTML = ''; if (inputText.trim() === '') { outputContainer.innerHTML = '<p class="text-gray-500 text-center">Bitte geben Sie Text ein, um Fancy Fonts zu generieren.</p>'; showMessage('Bitte geben Sie Text ein.', 'error'); variationsHeader.classList.add('hidden'); return; } let fontsToDisplay; if (isVariationMode && originalFontDetails) { fontsToDisplay = generateCharSubstitutionVariations(inputText, 5); variationsHeader.classList.remove('hidden'); } else { fontsToDisplay = FONT_MAPS; variationsHeader.classList.add('hidden'); } fontsToDisplay.forEach(font => { const textToDisplay = font.convertedText !== undefined ? font.convertedText : convertText(inputText, font); const fontType = font.type; const originalMapForVarying = font.map; const fontDiv = document.createElement('div'); fontDiv.className = 'bg-gray-50 p-4 rounded-lg shadow-sm border border-gray-200 flex flex-col sm:flex-row items-center justify-between gap-3'; const fontText = document.createElement('p'); fontText.className = 'text-gray-900 text-lg sm:text-xl md:text-2xl break-words flex-grow'; // Schriftgröße angepasst fontText.textContent = textToDisplay; fontText.style.wordBreak = 'break-all'; const varyBtn = document.createElement('button'); varyBtn.className = 'vary-button px-4 py-2 bg-white text-gray-700 text-sm font-medium rounded-md hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2 flex-shrink-0'; // Button-Stil angepasst varyBtn.textContent = 'Variieren'; varyBtn.onclick = () => { displayFancyFonts(inputText, true, { type: fontType, map: originalMapForVarying, convertedText: textToDisplay }); outputContainer.scrollIntoView({ behavior: 'smooth', block: 'start' }); }; fontDiv.appendChild(fontText); fontDiv.appendChild(varyBtn); outputContainer.appendChild(fontDiv); }); if (!isVariationMode) { outputContainer.scrollIntoView({ behavior: 'smooth', block: 'start' }); } } // Event-Listener für den Generieren-Button document.getElementById('generateButton').addEventListener('click', () => { const inputText = document.getElementById('inputText').value; displayFancyFonts(inputText, false, null); }); // Initialisierung mit einer Nachricht window.onload = () => { document.getElementById('outputContainer').innerHTML = '<p class="text-gray-500 text-center">Geben Sie etwas ein und klicken Sie auf \'Generieren\', um die Magie zu sehen!</p>'; }; </script> </body> </html>