diff --git a/.eslintrc.json b/.eslintrc.json index 003421b..308fadc 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -10,7 +10,7 @@ "sourceType": "script" }, "rules": { - "indent": ["error", 4], + "indent": "off", "linebreak-style": ["error", "unix"], "quotes": ["error", "single"], "semi": ["error", "always"], diff --git a/README.md b/README.md new file mode 100644 index 0000000..b196211 --- /dev/null +++ b/README.md @@ -0,0 +1,168 @@ +# Ǧ̴̝̲̙̱̳̗̱͊̒̀̀̀l̶̰̲̯̗̾̊͌̀̊̃̓̚i̴̧̘͕̺͉̘̇̃̄̏͂̃͛̎̐t̷̢̨̙̗̞̯͖̗̳͌c̷̖͓̟̞͋h̷̨̻̝̻̩̼̤̣̟̓͗̑͝C̴̺̺̘͍̙̈͐̀̾̔̈́̒̃r̷̢̧̢̛̬̱̻̝̭̈́̍̐͒̇ā̸̤̜͌̓̋̉̓̉̚f̸̘̘̤͙̠̈́̐̍̀͋͊̕͝t̸̨̹̪̭̲̮̗̳̽̎ + +> **Artisanal text corruption, served fresh!** + +Transform your boring text into b̴̧̧̯̰̲̤̫̲͇̅̀̓̆̈́̈́̄̀e̵̫̥̱̿̾̊̉͊́̚a̸̫̺̘̤̰̝̿̐̍͗̇̋u̸̢̳̝̯̲̮̦̇̍̔̈́̎̊t̸̨̲̘̺̹̙̋͆̀̅̚i̸̧̦̩̥̫̭̬̍̑̎́̒f̵̰̰̺̹̤̋ù̴̧̡̢̘̱̇͛̉̇̂͌l̶̺̩̰̥̀̉̄̄̈́͝ć̵̨̧̦̞̤̤̠̃́̔̀͝h̴̭̙̋̊̾͛́a̴̻̦̹̰̖̅̀͌̃ō̴̳̜̝̮͇͍̄̓̋͌̍̔s̷̘̺̤̩͂̽̌̅̈͠! GlitchCraft is a Progressive Web App that generates zalgo text using Unicode combining characters. + +## ✨ F̴̛̪̞̯̀̔́ͅe̷̮̮̗̣̎a̸̤̺̜̾̃̓͜t̶̛̘̝̾u̴̢̬͇̒ṛ̴̭̖̈́e̷̲̺̔̓͝ş̷̝̑̀ + +- **🎨 Six Corruption Modes**: From subtle glitches to complete chaos +- **📱 Mobile-First Design**: Perfect experience on all devices +- **⚡ Real-Time Generation**: See corruption as you type +- **📋 One-Click Copy**: Tap the output to copy instantly +- **🔧 Adjustable Intensity**: Fine-tune your chaos level (1-10) +- **💾 PWA Ready**: Install as an app, works offline +- **🌐 Universal Support**: Works on all modern browsers + +## 🎭 Corruption Modes + +| Mode | Example | Description | +|------|---------|-------------| +| **Full Chaos** | ĥ̵̝̮̀è̸̘̩l̴̹̩̔l̵̲̎ô̶̰ ̷̳̎w̸̰̄o̶̜̅r̷̰̄l̴̨̾d̶̰̈ | Balanced corruption above, middle, and below | +| **Above Only** | h̸̘̤́ë̸́l̴̮̆l̸̘̀ö̴́ ̶̘̀w̴̮̌ö̴́ř̶̰l̴̮̀d̸̮̆ | Marks above characters only | +| **Below Only** | h̴̖̆ë̵l̵̰l̵̲ö̴ ̷̰w̴̰ö̴̰r̴̲l̵̲d̴̰ | Marks below characters only | +| **Middle Only** | h̶e̷l̷l̶o̵ ̴w̵o̴r̷l̴d̵ | Marks overlaying characters | +| **Mini Glitch** | ḧ̴e̵l̴l̷o̵ ̴w̶o̴r̷l̴d̵ | Subtle corruption | +| **Heavy Corruption** | h̸̨̬̘̤̖̱̗̘̄̀́̌̈́̀̇̚ë̴̛̖̘̩̰̱̳̤́̓̒̚l̷̢̧̰̲̫̲̝̹̈́̔̃̀̈́̇̚l̴̢̧̰̲̫̲̝̹̈́̔̃̀̈́̇̚ö̴́̓̒̚ ̷̰̔̈́w̸̰̄̌ö̴́̓̒̚r̷̰̄̌l̴̰̔̈́d̶̰̈́̌ | Maximum chaos overload | + +## 🚀 Quick Start + +### 🌐 Online +Visit the deployed app at: **[Your deployment URL]** + +### 💻 Local Development + +```bash +# Clone the repository +git clone +cd zalgo + +# Install dependencies +just install +# or: bun install + +# Start development server +just serve +# or: python3 server.py + +# Open http://localhost:8000 +``` + +## 🛠️ Development + +### Prerequisites +- **Bun** (for dependencies and linting) +- **Python 3** (for development server) +- **Just** (for task automation, optional) + +### Available Commands + +```bash +# Development +just serve # Start development server +just serve-bg # Start server in background +just stop # Stop background server + +# Code Quality +just lint-all # Lint JavaScript and Python +just format-all # Format all code +just check-all # Run all linting and validation + +# Testing & Validation +just validate # Full validation suite +just validate-references # Check file references exist +just validate-html # Validate HTML (requires Java) +just validate-manifest # Validate PWA manifest + +# PWA Icons +just icons-png # Generate PNG icons (requires canvas) +just icons-browser # Open browser icon generator + +# Project Info +just info # Show project information +just status # Check server status +``` + +## 📱 Mobile Experience + +GlitchCraft is designed mobile-first with: + +- **Touch-optimized controls** with larger touch targets +- **Responsive layout** that adapts from 320px to 4K +- **iOS zoom prevention** with proper font sizes +- **Haptic feedback** for copy actions (where supported) +- **Full-screen support** when installed as PWA +- **Offline functionality** via service worker + +### Mobile Features +- Tap output text to copy instantly +- Swipe-friendly interface +- Portrait and landscape support +- Works great on tablets + +## 🔧 Technical Details + +### Architecture +- **Pure JavaScript** - No frameworks, maximum performance +- **Service Worker** - Full offline support with cache-first strategy +- **Progressive Enhancement** - Works without JavaScript +- **Accessible** - Screen reader compatible, keyboard navigation + +### Zalgo Algorithm +The corruption engine uses Unicode combining diacritical marks from three categories: +- **Above** (U+0300-U+036F): Accents and marks above characters +- **Middle** (U+0315-U+0489): Overlaying marks +- **Below** (U+0316-U+0359): Marks below characters + +Each mode strategically applies different combinations for unique effects. + +### Browser Support +- ✅ Chrome/Chromium 88+ +- ✅ Firefox 85+ +- ✅ Safari 14+ +- ✅ Edge 88+ +- ✅ Mobile browsers (iOS Safari, Chrome Mobile) + +## 🎨 Examples + +Here are some z̴̳̈a̸̭̾l̵̰̔g̶̱̈ó̴̬ ̷̲̎t̸̰̄e̶̮̾x̷̲̄ẗ̴̰ examples: + +### Normal Text → Corrupted +``` +Hello World → H̸̖̄e̶̮̾l̵̰̔ḻ̶̈ó̴̬ ̷̲̎W̸̰̄ö̶̮̾r̵̰̔ḻ̶̈d̴̬̈ + +Welcome to GlitchCraft → Ẁ̴̛̪̞̯̔́ͅe̷̮̮̗̣̎l̴̹̩̔c̸̘̩̀ö̴̝̮̀m̵̲̎ë̸̘̩ ̶̰̔t̷̳̎ő̶̰ ̴̨̾G̴̮̀l̸̘̀i̵̲t̴̖̆c̵̰h̴̘Č̶̮r̴̮̀a̵̲f̴̰t̸̮̆ + +The quick brown fox → T̷̨̄h̶̨̍ë̴́ ̵̌q̷̇ű̴i̸̇c̸̈ǩ̶ ̴̈b̵̄ř̷ö̴́ẇ̸n̶̈ ̴̌f̷̄ö̴́ẋ̸ +``` + +### Heavy Corruption Mode +``` +CHAOS → C̸̨̧̬̘̤̖̱̗̘̄̀́̌̈́̀̇̚Ḧ̷̢̧̰̲̫̲̝̹́̔̃̀̈́̇̚Ä̴̢̧̰̲̫̲̝̹́̔̃̀̈́̇̚Ö̷̰́̓̒̚S̷̰̔̈́ +``` + +## 🤝 Contributing + +1. Fork the repository +2. Create a feature branch +3. Make your changes +4. Run `just check-all` to ensure quality +5. Submit a pull request + +## 📄 License + +MIT License - Feel free to use this for your own projects! + +## 🎭 Fun Facts + +- The name "zalgo" comes from a creepypasta character +- Unicode combining characters were designed for legitimate text rendering +- GlitchCraft generates infinite unique corruptions +- The glitch animations are pure CSS - no JavaScript! +- Works offline once loaded (thanks to service worker) + +--- + +**Made with ❤️ and ḉ̴̨̧̰̲̫̲̝̹̈́̔̃̀̈́̇̚h̷̰̔̈́ä̸̰́̌ō̶̰̔̈́s̷̰̔̈́** + +*Transform your text, embrace the glitch, spread the chaos!* \ No newline at end of file diff --git a/app/app.js b/app/app.js index d151350..7e73d09 100644 --- a/app/app.js +++ b/app/app.js @@ -13,6 +13,7 @@ const inputText = document.getElementById('inputText'); const outputText = document.getElementById('outputText'); const intensitySlider = document.getElementById('intensity'); const intensityValue = document.getElementById('intensityValue'); +const zalgoModeSelect = document.getElementById('zalgoMode'); const clearBtn = document.getElementById('clearBtn'); const copyNotification = document.getElementById('copyNotification'); @@ -22,9 +23,10 @@ const copyNotification = document.getElementById('copyNotification'); function updateOutput() { const text = inputText.value; const intensity = parseInt(intensitySlider.value); + const mode = zalgoModeSelect.value; if (text) { - outputText.value = zalgo.generate(text, intensity); + outputText.value = zalgo.generate(text, intensity, mode); } else { outputText.value = ''; } @@ -74,6 +76,8 @@ intensitySlider.addEventListener('input', () => { updateOutput(); }); +zalgoModeSelect.addEventListener('change', updateOutput); + outputText.addEventListener('click', copyToClipboard); clearBtn.addEventListener('click', clearAll); diff --git a/app/index.html b/app/index.html index b4703c7..a8dc4f4 100644 --- a/app/index.html +++ b/app/index.html @@ -24,9 +24,23 @@
- - - 5 +
+ + +
+ +
+ + + 5 +
diff --git a/app/styles.css b/app/styles.css index 7099903..26d23a7 100644 --- a/app/styles.css +++ b/app/styles.css @@ -96,8 +96,8 @@ h1 { .controls { display: flex; - align-items: center; - gap: 15px; + flex-wrap: wrap; + gap: 20px; margin-bottom: 30px; padding: 20px; background: var(--bg-tertiary); @@ -105,9 +105,42 @@ h1 { border: 1px solid var(--border); } +.control-group { + display: flex; + align-items: center; + gap: 10px; + flex: 1; + min-width: 200px; +} + .controls label { color: var(--text-secondary); font-size: 0.95rem; + white-space: nowrap; + min-width: 80px; +} + +#zalgoMode { + flex: 1; + padding: 8px 12px; + background: var(--bg-primary); + border: 2px solid var(--border); + border-radius: 8px; + color: var(--text-primary); + font-size: 0.95rem; + outline: none; + transition: all 0.3s ease; + min-width: 120px; +} + +#zalgoMode:focus { + border-color: var(--accent); + box-shadow: 0 0 10px var(--shadow); +} + +#zalgoMode option { + background: var(--bg-primary); + color: var(--text-primary); } #intensity { @@ -277,24 +310,126 @@ footer p { } /* Mobile responsiveness */ -@media (max-width: 600px) { +@media (max-width: 768px) { + body { + padding: 10px; + } + .container { - padding: 25px; + padding: 20px; + max-width: 100%; } h1 { font-size: 2rem; } + .subtitle { + font-size: 1rem; + } + .controls { + flex-direction: column; + gap: 15px; + padding: 15px; + } + + .control-group { flex-direction: column; align-items: stretch; - gap: 10px; + gap: 8px; + min-width: auto; + } + + .controls label { + min-width: auto; + font-size: 0.9rem; + } + + #zalgoMode { + width: 100%; + padding: 12px; + font-size: 1rem; + min-width: auto; + } + + #intensity { + width: 100%; + height: 8px; + } + + #intensity::-webkit-slider-thumb { + width: 24px; + height: 24px; + } + + #intensity::-moz-range-thumb { + width: 24px; + height: 24px; + } + + textarea { + min-height: 140px; + font-size: 1rem; + padding: 15px; + } + + .clear-btn { + padding: 18px; + font-size: 1.1rem; + } + + .copy-notification { + padding: 15px 25px; + font-size: 1rem; + } +} + +/* Small mobile devices */ +@media (max-width: 480px) { + .container { + padding: 15px; + } + + h1 { + font-size: 1.8rem; + } + + .controls { + padding: 12px; + gap: 12px; } textarea { min-height: 120px; - font-size: 0.95rem; + font-size: 16px; /* Prevents zoom on iOS */ + } + + #zalgoMode { + font-size: 16px; /* Prevents zoom on iOS */ + } +} + +/* Touch-friendly improvements */ +@media (hover: none) and (pointer: coarse) { + /* Touch device specific styles */ + textarea { + font-size: 16px; /* Prevents zoom on mobile browsers */ + } + + #zalgoMode { + font-size: 16px; + padding: 15px; + } + + .clear-btn { + min-height: 48px; /* Minimum touch target size */ + } + + #outputText { + cursor: pointer; + -webkit-user-select: all; + user-select: all; } } diff --git a/app/zalgo.js b/app/zalgo.js index 5bfba06..b0021b7 100644 --- a/app/zalgo.js +++ b/app/zalgo.js @@ -215,12 +215,13 @@ class ZalgoGenerator { } /** - * Generate zalgo text with specified intensity + * 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) { + generate(text, intensity = 5, mode = 'full') { if (!text) return ''; // Normalize intensity to 1-10 range @@ -236,20 +237,52 @@ class ZalgoGenerator { continue; } - // Calculate how many combining characters to add based on intensity - // Higher intensity = more corruption + // Calculate how many combining characters to add based on intensity and mode const factor = intensity / 10; - // Add characters above (0-3 based on intensity) - const aboveCount = Math.floor(Math.random() * (4 * factor)); + 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); - - // Add characters in middle (0-2 based on intensity) - const middleCount = Math.floor(Math.random() * (3 * factor)); result += this.randomChars(this.middle, middleCount); - - // Add characters below (0-3 based on intensity) - const belowCount = Math.floor(Math.random() * (4 * factor)); result += this.randomChars(this.below, belowCount); }