glitchcraft/app/zalgo.js
Ole-Morten Duesund 7b0a3746d5 Enhance mobile experience and add zalgo text variants
Mobile improvements:
- Comprehensive responsive design for 320px-4K screens
- Touch-optimized controls with larger touch targets
- iOS zoom prevention with 16px font sizes on inputs
- Swipe-friendly interface with better spacing
- Portrait and landscape orientation support
- Enhanced accessibility with better contrast and sizes

Zalgo variants implemented:
- Full Chaos: Balanced corruption (default)
- Above Only: Marks above characters only
- Below Only: Marks below characters only
- Middle Only: Overlaying marks
- Mini Glitch: Subtle corruption
- Heavy Corruption: Maximum chaos overload

UI enhancements:
- Added corruption mode selector dropdown
- Reorganized controls into responsive groups
- Improved mobile control layouts
- Better visual hierarchy and spacing

Code quality:
- Fixed ESLint/Prettier indentation conflict
- Enhanced ZalgoGenerator with mode parameter
- Added event handlers for mode selection
- Comprehensive mobile CSS with multiple breakpoints

Documentation:
- Created comprehensive README with zalgo examples
- Documented all corruption modes with examples
- Added development and deployment instructions

The app now provides a perfect mobile experience with
diverse zalgo corruption options for creative text effects.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-18 20:30:05 +02:00

301 lines
7.7 KiB
JavaScript

/**
* Zalgo Text Generator
* Generates corrupted/glitched text using Unicode combining characters
*/
/* exported ZalgoGenerator */
/* eslint-disable-next-line no-unused-vars */
class ZalgoGenerator {
constructor() {
// Combining diacritical marks that appear above characters
this.above = [
'\u0300',
'\u0301',
'\u0302',
'\u0303',
'\u0304',
'\u0305',
'\u0306',
'\u0307',
'\u0308',
'\u0309',
'\u030A',
'\u030B',
'\u030C',
'\u030D',
'\u030E',
'\u030F',
'\u0310',
'\u0311',
'\u0312',
'\u0313',
'\u0314',
'\u0315',
'\u0316',
'\u0317',
'\u0318',
'\u0319',
'\u031A',
'\u031B',
'\u031C',
'\u031D',
'\u031E',
'\u031F',
'\u0320',
'\u0321',
'\u0322',
'\u0323',
'\u0324',
'\u0325',
'\u0326',
'\u0327',
'\u0328',
'\u0329',
'\u032A',
'\u032B',
'\u032C',
'\u032D',
'\u032E',
'\u032F',
'\u0330',
'\u0331',
'\u0332',
'\u0333',
'\u0334',
'\u0335',
'\u0336',
'\u0337',
'\u0338',
'\u0339',
'\u033A',
'\u033B',
'\u033C',
'\u033D',
'\u033E',
'\u033F',
'\u0340',
'\u0341',
'\u0342',
'\u0343',
'\u0344',
'\u0345',
'\u0346',
'\u0347',
'\u0348',
'\u0349',
'\u034A',
'\u034B',
'\u034C',
'\u034D',
'\u034E',
'\u034F',
'\u0350',
'\u0351',
'\u0352',
'\u0353',
'\u0354',
'\u0355',
'\u0356',
'\u0357',
'\u0358',
'\u0359',
'\u035A',
'\u035B',
'\u035C',
'\u035D',
'\u035E',
'\u035F',
'\u0360',
'\u0361',
'\u0362',
'\u0363',
'\u0364',
'\u0365',
'\u0366',
'\u0367',
'\u0368',
'\u0369',
'\u036A',
'\u036B',
'\u036C',
'\u036D',
'\u036E',
'\u036F',
];
// Combining diacritical marks that appear in the middle
this.middle = [
'\u0315',
'\u031B',
'\u0340',
'\u0341',
'\u0358',
'\u0321',
'\u0322',
'\u0327',
'\u0328',
'\u0334',
'\u0335',
'\u0336',
'\u034F',
'\u035C',
'\u035D',
'\u035E',
'\u035F',
'\u0360',
'\u0362',
'\u0338',
'\u0337',
'\u0361',
'\u0489',
];
// Combining diacritical marks that appear below characters
this.below = [
'\u0316',
'\u0317',
'\u0318',
'\u0319',
'\u031C',
'\u031D',
'\u031E',
'\u031F',
'\u0320',
'\u0324',
'\u0325',
'\u0326',
'\u0329',
'\u032A',
'\u032B',
'\u032C',
'\u032D',
'\u032E',
'\u032F',
'\u0330',
'\u0331',
'\u0332',
'\u0333',
'\u0339',
'\u033A',
'\u033B',
'\u033C',
'\u0345',
'\u0347',
'\u0348',
'\u0349',
'\u034D',
'\u034E',
'\u0353',
'\u0354',
'\u0355',
'\u0356',
'\u0359',
'\u035A',
'\u0323',
];
}
/**
* Get a random character from an array
*/
randomChar(array) {
return array[Math.floor(Math.random() * array.length)];
}
/**
* Generate a specified number of random characters from an array
*/
randomChars(array, count) {
let result = '';
for (let i = 0; i < count; i++) {
result += this.randomChar(array);
}
return result;
}
/**
* Generate zalgo text with specified intensity and mode
* @param {string} text - The input text to corrupt
* @param {number} intensity - Corruption intensity (1-10)
* @param {string} mode - Corruption mode (full, above, below, middle, mini, heavy)
* @returns {string} - The corrupted zalgo text
*/
generate(text, intensity = 5, mode = 'full') {
if (!text) return '';
// Normalize intensity to 1-10 range
intensity = Math.max(1, Math.min(10, intensity));
let result = '';
for (let char of text) {
result += char;
// Skip whitespace and newlines
if (/\s/.test(char)) {
continue;
}
// Calculate how many combining characters to add based on intensity and mode
const factor = intensity / 10;
let aboveCount = 0;
let middleCount = 0;
let belowCount = 0;
switch (mode) {
case 'above':
aboveCount = Math.floor(Math.random() * (6 * factor));
break;
case 'below':
belowCount = Math.floor(Math.random() * (6 * factor));
break;
case 'middle':
middleCount = Math.floor(Math.random() * (4 * factor));
break;
case 'mini':
// Light corruption - fewer characters
aboveCount = Math.floor(Math.random() * (2 * factor));
middleCount = Math.floor(Math.random() * (1 * factor));
belowCount = Math.floor(Math.random() * (2 * factor));
break;
case 'heavy':
// Heavy corruption - more characters
aboveCount = Math.floor(Math.random() * (8 * factor)) + 1;
middleCount = Math.floor(Math.random() * (5 * factor)) + 1;
belowCount = Math.floor(Math.random() * (8 * factor)) + 1;
break;
case 'full':
default:
// Balanced corruption
aboveCount = Math.floor(Math.random() * (4 * factor));
middleCount = Math.floor(Math.random() * (3 * factor));
belowCount = Math.floor(Math.random() * (4 * factor));
break;
}
// Add the calculated characters
result += this.randomChars(this.above, aboveCount);
result += this.randomChars(this.middle, middleCount);
result += this.randomChars(this.below, belowCount);
}
return result;
}
/**
* Remove zalgo corruption from text
* @param {string} text - The corrupted text
* @returns {string} - Clean text without combining characters
*/
clean(text) {
// Remove all combining characters (Unicode category Mn)
return text.replace(/[\u0300-\u036f\u0489]/g, '');
}
}