@whykusanagi/corrupted-theme 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/README.md +6 -0
  3. package/docs/CHARACTER_LEVEL_CORRUPTION.md +264 -0
  4. package/docs/CORRUPTION_PHRASES.md +529 -0
  5. package/docs/ROADMAP.md +266 -0
  6. package/docs/STYLE_GUIDE.md +605 -0
  7. package/docs/brand/BRAND_OVERVIEW.md +413 -0
  8. package/docs/brand/COLOR_SYSTEM.md +583 -0
  9. package/docs/brand/DESIGN_TOKENS.md +1009 -0
  10. package/docs/brand/TRANSLATION_FAILURE_AESTHETIC.md +525 -0
  11. package/docs/brand/TYPOGRAPHY.md +624 -0
  12. package/docs/components/ANIMATION_GUIDELINES.md +901 -0
  13. package/docs/components/COMPONENT_LIBRARY.md +1061 -0
  14. package/docs/components/GLASSMORPHISM.md +602 -0
  15. package/docs/components/INTERACTIVE_STATES.md +766 -0
  16. package/docs/governance/CONTRIBUTION_GUIDELINES.md +593 -0
  17. package/docs/governance/DESIGN_SYSTEM_GOVERNANCE.md +451 -0
  18. package/docs/governance/VERSION_MANAGEMENT.md +447 -0
  19. package/docs/governance/VERSION_REFERENCES.md +229 -0
  20. package/docs/platforms/COMPONENT_MAPPING.md +579 -0
  21. package/docs/platforms/NPM_PACKAGE.md +854 -0
  22. package/docs/platforms/WEB_IMPLEMENTATION.md +1221 -0
  23. package/docs/standards/ACCESSIBILITY.md +715 -0
  24. package/docs/standards/ANTI_PATTERNS.md +554 -0
  25. package/docs/standards/SPACING_SYSTEM.md +549 -0
  26. package/examples/button.html +1 -1
  27. package/examples/card.html +1 -1
  28. package/examples/form.html +1 -1
  29. package/examples/index.html +2 -2
  30. package/examples/layout.html +1 -1
  31. package/examples/nikke-team-builder.html +1 -1
  32. package/examples/showcase-complete.html +840 -15
  33. package/examples/showcase.html +1 -1
  34. package/package.json +16 -3
  35. package/src/css/components.css +676 -0
  36. package/src/lib/character-corruption.js +563 -0
  37. package/src/lib/components.js +283 -0
@@ -0,0 +1,563 @@
1
+ /**
2
+ * Character-Level Japanese Corruption
3
+ * Matches Celeste CLI's CorruptTextJapanese() implementation
4
+ *
5
+ * This system provides character-level mixing of Japanese characters INTO English text,
6
+ * creating the "translation-failure" aesthetic that defines the Celeste brand.
7
+ *
8
+ * Use Cases:
9
+ * - Dashboard titles and headers
10
+ * - Section labels and UI text
11
+ * - Navigation items
12
+ * - Any text that needs to match CLI branding
13
+ *
14
+ * For loading animations and dramatic effects, use corrupted-text.js instead.
15
+ *
16
+ * @module character-corruption
17
+ * @version 1.0.0
18
+ * @see docs/brand/TRANSLATION_FAILURE_AESTHETIC.md
19
+ */
20
+
21
+ /**
22
+ * Intensity constants matching CLI implementation
23
+ *
24
+ * IMPORTANT: Never exceed 45% intensity for readable UI text.
25
+ * Higher intensities violate WCAG accessibility guidelines.
26
+ *
27
+ * @constant {Object} INTENSITY
28
+ */
29
+ export const INTENSITY = {
30
+ /** No corruption (0%) - Original text */
31
+ NONE: 0.0,
32
+
33
+ /** Minimal corruption (15%) - Subtle, decorative only */
34
+ MINIMAL: 0.15,
35
+
36
+ /** Low corruption (25%) - Section headers, readable with aesthetic */
37
+ LOW: 0.25,
38
+
39
+ /** Medium corruption (35%) - Dashboard titles, brand elements (RECOMMENDED) */
40
+ MEDIUM: 0.35,
41
+
42
+ /** High corruption (45%) - Loading screens, dramatic effects (MAXIMUM) */
43
+ HIGH: 0.45,
44
+
45
+ /** Maximum readable intensity - Never exceed this threshold */
46
+ MAX_READABLE: 0.45
47
+ };
48
+
49
+ /**
50
+ * Character sets for corruption
51
+ * Organized by usage frequency to match CLI behavior
52
+ * @private
53
+ */
54
+ const CHARACTER_SETS = {
55
+ // Katakana - 50% of replacements (foreign words, phonetics)
56
+ katakana: [
57
+ 'ア', 'イ', 'ウ', 'エ', 'オ',
58
+ 'カ', 'キ', 'ク', 'ケ', 'コ',
59
+ 'サ', 'シ', 'ス', 'セ', 'ソ',
60
+ 'タ', 'チ', 'ツ', 'テ', 'ト',
61
+ 'ナ', 'ニ', 'ヌ', 'ネ', 'ノ',
62
+ 'ハ', 'ヒ', 'フ', 'ヘ', 'ホ',
63
+ 'マ', 'ミ', 'ム', 'メ', 'モ',
64
+ 'ヤ', 'ユ', 'ヨ',
65
+ 'ラ', 'リ', 'ル', 'レ', 'ロ',
66
+ 'ワ', 'ヲ', 'ン', 'ー'
67
+ ],
68
+
69
+ // Kanji - 25% of replacements (semantic/meaning-based)
70
+ // Selected for contextual relevance to common UI terms
71
+ kanji: [
72
+ '使', '用', // use/usage (shiyō)
73
+ '統', '計', // statistics (tōkei)
74
+ '理', '処', // logic/process (ri/shori)
75
+ '分', '析', // analyze (bunseki)
76
+ '監', '視', // watch/supervise (kanshi)
77
+ '接', '続', // connect/continue (setsuzoku)
78
+ '読', '込', // read/load (yomikomi)
79
+ '実', '行', // execute (jikkō)
80
+ '壊', '腐', // broken/corrupt (kowasu/fuhai)
81
+ '虚', '空', // void (kokū)
82
+ '深', '淵', // abyss (shin'en)
83
+ '闇' // darkness (yami)
84
+ ],
85
+
86
+ // Hiragana - 10% of replacements (rare, grammatical)
87
+ hiragana: [
88
+ 'あ', 'い', 'う', 'え', 'お',
89
+ 'か', 'き', 'く', 'け', 'こ',
90
+ 'さ', 'し', 'す', 'せ', 'そ',
91
+ 'た', 'ち', 'つ', 'て', 'と'
92
+ ]
93
+ };
94
+
95
+ /**
96
+ * Corrupt text with character-level Japanese mixing
97
+ *
98
+ * This function implements the core translation-failure aesthetic by randomly
99
+ * replacing English characters with Japanese characters (Katakana, Kanji, Hiragana)
100
+ * at the specified intensity level.
101
+ *
102
+ * @param {string} text - English text to corrupt
103
+ * @param {number} [intensity=0.3] - Corruption intensity (0.0-0.45)
104
+ * @returns {string} Corrupted text with Japanese characters mixed in
105
+ *
106
+ * @example
107
+ * // Dashboard title (recommended intensity)
108
+ * corruptTextJapanese('USAGE ANALYTICS', INTENSITY.MEDIUM);
109
+ * // => "US使AGE ANア統LYTICS"
110
+ *
111
+ * @example
112
+ * // Section header (lighter intensity)
113
+ * corruptTextJapanese('Provider Breakdown', INTENSITY.LOW);
114
+ * // => "Pro理vider Brea統kdown"
115
+ *
116
+ * @example
117
+ * // Original text (no corruption)
118
+ * corruptTextJapanese('Loading', INTENSITY.NONE);
119
+ * // => "Loading"
120
+ */
121
+ export function corruptTextJapanese(text, intensity = 0.3) {
122
+ // Validate intensity
123
+ if (intensity < 0 || intensity > INTENSITY.MAX_READABLE) {
124
+ console.warn(
125
+ `[character-corruption] Intensity ${intensity} outside recommended range (0-${INTENSITY.MAX_READABLE}). ` +
126
+ `Clamping to safe value.`
127
+ );
128
+ intensity = Math.max(0, Math.min(intensity, INTENSITY.MAX_READABLE));
129
+ }
130
+
131
+ // Early return for no corruption
132
+ if (intensity === 0) {
133
+ return text;
134
+ }
135
+
136
+ const chars = text.split('');
137
+ let result = '';
138
+
139
+ for (let i = 0; i < chars.length; i++) {
140
+ const char = chars[i];
141
+
142
+ // Skip spaces, punctuation, digits, and non-letters
143
+ if (!/[a-zA-Z]/.test(char)) {
144
+ result += char;
145
+ continue;
146
+ }
147
+
148
+ // Apply corruption based on intensity (random chance)
149
+ if (Math.random() < intensity) {
150
+ const roll = Math.random();
151
+
152
+ if (roll < 0.5) {
153
+ // 50%: Katakana replacement (most common)
154
+ result += CHARACTER_SETS.katakana[
155
+ Math.floor(Math.random() * CHARACTER_SETS.katakana.length)
156
+ ];
157
+ } else if (roll < 0.75) {
158
+ // 25%: Kanji replacement (semantic/contextual)
159
+ result += CHARACTER_SETS.kanji[
160
+ Math.floor(Math.random() * CHARACTER_SETS.kanji.length)
161
+ ];
162
+ } else if (roll < 0.90) {
163
+ // 15%: Keep original + maybe insert Katakana after
164
+ result += char;
165
+ if (Math.random() < 0.3) {
166
+ result += CHARACTER_SETS.katakana[
167
+ Math.floor(Math.random() * CHARACTER_SETS.katakana.length)
168
+ ];
169
+ }
170
+ } else {
171
+ // 10%: Hiragana replacement (rare)
172
+ result += CHARACTER_SETS.hiragana[
173
+ Math.floor(Math.random() * CHARACTER_SETS.hiragana.length)
174
+ ];
175
+ }
176
+ } else {
177
+ // No corruption - keep original character
178
+ result += char;
179
+ }
180
+ }
181
+
182
+ return result;
183
+ }
184
+
185
+ /**
186
+ * Semantic corruption with context-aware character selection
187
+ *
188
+ * Future enhancement (v0.2.0): Uses context hints to select semantically
189
+ * appropriate Japanese characters. For example, "loading" would prefer
190
+ * characters related to reading/loading (読み込み).
191
+ *
192
+ * Currently falls back to standard corruption.
193
+ *
194
+ * @param {string} text - Text to corrupt
195
+ * @param {string} [context='default'] - Context hint (loading, processing, analyzing, corrupting, etc.)
196
+ * @param {number} [intensity=0.3] - Corruption intensity
197
+ * @returns {string} Contextually corrupted text
198
+ *
199
+ * @example
200
+ * corruptTextSemantic('Loading', 'loading', INTENSITY.MEDIUM);
201
+ * // Future: Will prefer 読, 込, ロ, ー, ド characters
202
+ * // Current: Falls back to corruptTextJapanese()
203
+ */
204
+ export function corruptTextSemantic(text, context = 'default', intensity = 0.3) {
205
+ // TODO: Implement context-aware character selection in v0.2.0
206
+ // Context mappings:
207
+ // - loading: 読, 込, ロ, ー, ド
208
+ // - processing: 処, 理, プ, ロ, セ, ス
209
+ // - analyzing: 分, 析, 解
210
+ // - corrupting: 壊, 腐, 敗
211
+ // - watching: 監, 視, 見
212
+ // - connecting: 接, 続, 繋
213
+
214
+ // For now, fallback to standard corruption
215
+ return corruptTextJapanese(text, intensity);
216
+ }
217
+
218
+ /**
219
+ * Auto-corrupt DOM elements with data attributes
220
+ *
221
+ * Finds all elements with class="auto-corrupt" and automatically applies
222
+ * character-level corruption based on data attributes.
223
+ *
224
+ * Supported data attributes:
225
+ * - data-text: Original text to corrupt (defaults to element.textContent)
226
+ * - data-intensity: Corruption intensity (0.0-0.45, defaults to 0.35)
227
+ * - data-interval: Re-corruption interval in ms (0 = no repeat, default: 3000)
228
+ *
229
+ * @example
230
+ * <h1 class="auto-corrupt"
231
+ * data-text="USAGE ANALYTICS"
232
+ * data-intensity="0.35"
233
+ * data-interval="3000">
234
+ * USAGE ANALYTICS
235
+ * </h1>
236
+ *
237
+ * <script type="module">
238
+ * import { initAutoCorruption } from './character-corruption.js';
239
+ * initAutoCorruption();
240
+ * </script>
241
+ */
242
+ export function initAutoCorruption() {
243
+ const elements = document.querySelectorAll('.auto-corrupt');
244
+
245
+ if (elements.length === 0) {
246
+ return;
247
+ }
248
+
249
+ elements.forEach(element => {
250
+ // Skip if already initialized
251
+ if (element.dataset.corruptionInitialized === 'true') {
252
+ return;
253
+ }
254
+
255
+ const originalText = element.dataset.text || element.textContent.trim();
256
+ const intensity = parseFloat(element.dataset.intensity) || INTENSITY.MEDIUM;
257
+ const interval = parseInt(element.dataset.interval) || 3000;
258
+
259
+ // Initial corruption
260
+ element.textContent = corruptTextJapanese(originalText, intensity);
261
+
262
+ // Re-corrupt on interval (show randomization)
263
+ if (interval > 0) {
264
+ const intervalId = setInterval(() => {
265
+ // Check if element still exists in DOM
266
+ if (!document.contains(element)) {
267
+ clearInterval(intervalId);
268
+ return;
269
+ }
270
+ element.textContent = corruptTextJapanese(originalText, intensity);
271
+ }, interval);
272
+
273
+ // Store interval ID for cleanup
274
+ element.dataset.corruptionIntervalId = intervalId;
275
+ }
276
+
277
+ // Mark as initialized
278
+ element.dataset.corruptionInitialized = 'true';
279
+ });
280
+ }
281
+
282
+ /**
283
+ * Stop auto-corruption for a specific element
284
+ *
285
+ * @param {HTMLElement} element - Element to stop corrupting
286
+ */
287
+ export function stopAutoCorruption(element) {
288
+ if (element.dataset.corruptionIntervalId) {
289
+ clearInterval(parseInt(element.dataset.corruptionIntervalId));
290
+ delete element.dataset.corruptionIntervalId;
291
+ delete element.dataset.corruptionInitialized;
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Restart auto-corruption for a specific element
297
+ *
298
+ * @param {HTMLElement} element - Element to restart corruption
299
+ */
300
+ export function restartAutoCorruption(element) {
301
+ stopAutoCorruption(element);
302
+ const originalText = element.dataset.text || element.textContent.trim();
303
+ const intensity = parseFloat(element.dataset.intensity) || INTENSITY.MEDIUM;
304
+ const interval = parseInt(element.dataset.interval) || 3000;
305
+
306
+ element.textContent = corruptTextJapanese(originalText, intensity);
307
+
308
+ if (interval > 0) {
309
+ const intervalId = setInterval(() => {
310
+ if (!document.contains(element)) {
311
+ clearInterval(intervalId);
312
+ return;
313
+ }
314
+ element.textContent = corruptTextJapanese(originalText, intensity);
315
+ }, interval);
316
+
317
+ element.dataset.corruptionIntervalId = intervalId;
318
+ element.dataset.corruptionInitialized = 'true';
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Utility: Create a corrupted text element
324
+ *
325
+ * @param {string} text - Original text
326
+ * @param {Object} [options={}] - Configuration options
327
+ * @param {number} [options.intensity=0.35] - Corruption intensity
328
+ * @param {number} [options.interval=3000] - Re-corruption interval (0 = no repeat)
329
+ * @param {string} [options.className=''] - Additional CSS classes
330
+ * @param {string} [options.tag='span'] - HTML tag to create
331
+ * @returns {HTMLElement} Created element with auto-corruption
332
+ *
333
+ * @example
334
+ * const title = createCorruptedElement('USAGE ANALYTICS', {
335
+ * intensity: INTENSITY.MEDIUM,
336
+ * interval: 3000,
337
+ * className: 'text-accent',
338
+ * tag: 'h1'
339
+ * });
340
+ * document.body.appendChild(title);
341
+ */
342
+ export function createCorruptedElement(text, options = {}) {
343
+ const {
344
+ intensity = INTENSITY.MEDIUM,
345
+ interval = 3000,
346
+ className = '',
347
+ tag = 'span'
348
+ } = options;
349
+
350
+ const element = document.createElement(tag);
351
+ element.className = `auto-corrupt ${className}`.trim();
352
+ element.dataset.text = text;
353
+ element.dataset.intensity = intensity.toString();
354
+ element.dataset.interval = interval.toString();
355
+ element.textContent = text;
356
+
357
+ // Initialize corruption immediately
358
+ element.textContent = corruptTextJapanese(text, intensity);
359
+
360
+ if (interval > 0) {
361
+ const intervalId = setInterval(() => {
362
+ if (!document.contains(element)) {
363
+ clearInterval(intervalId);
364
+ return;
365
+ }
366
+ element.textContent = corruptTextJapanese(text, intensity);
367
+ }, interval);
368
+ element.dataset.corruptionIntervalId = intervalId;
369
+ }
370
+
371
+ element.dataset.corruptionInitialized = 'true';
372
+
373
+ return element;
374
+ }
375
+
376
+ // Auto-initialize on DOM ready
377
+ if (typeof window !== 'undefined') {
378
+ const initWhenReady = () => {
379
+ if (document.querySelector('.auto-corrupt')) {
380
+ initAutoCorruption();
381
+ }
382
+ };
383
+
384
+ if (document.readyState === 'loading') {
385
+ document.addEventListener('DOMContentLoaded', initWhenReady);
386
+ } else {
387
+ initWhenReady();
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Official Corruption Phrases
393
+ * From docs/CORRUPTION_PHRASES.md - Complete branding library
394
+ *
395
+ * Use these for consistent messaging across applications.
396
+ * Mix technical and personality phrases based on context.
397
+ */
398
+
399
+ /**
400
+ * Technical corruption phrases for UI/Dashboard
401
+ * Use for: Headers, status messages, data labels, functional text
402
+ */
403
+ export const CORRUPTION_PHRASES = {
404
+ // Loading states
405
+ loading: [
406
+ "ロード loading 読み込み中...",
407
+ "loaディング data...",
408
+ "読み込み yomikomi プロセス...",
409
+ "ロード rōdo in progress...",
410
+ "待機 waiting taiki..."
411
+ ],
412
+
413
+ // Processing states
414
+ processing: [
415
+ "処理 processing purosesu...",
416
+ "pro理cessing request...",
417
+ "処理中 shori-chū...",
418
+ "プロセス process active...",
419
+ "実行 executing jikkō..."
420
+ ],
421
+
422
+ // Analyzing states
423
+ analyzing: [
424
+ "分析 analyzing bunseki...",
425
+ "ana分lysing data...",
426
+ "解析 kaiseki in progress...",
427
+ "分析中 bunseki-chū...",
428
+ "データ data 解析 analysis..."
429
+ ],
430
+
431
+ // Corrupting states (Celeste-specific)
432
+ corrupting: [
433
+ "壊れ corrupting kowarete...",
434
+ "cor壊rupting system...",
435
+ "壊れている kowarete-iru...",
436
+ "corruption 壊れ active...",
437
+ "深淵 abyss 壊れ corruption..."
438
+ ],
439
+
440
+ // Watching/monitoring
441
+ watching: [
442
+ "👁️ 監視 watching kanshi 👁️",
443
+ "wat監ching system...",
444
+ "監視中 kanshi-chū...",
445
+ "観察 observing kansatsu...",
446
+ "👁️ 見ている miteiru 👁️"
447
+ ],
448
+
449
+ // Void/Abyss theme
450
+ void: [
451
+ "深淵 deep abyss shinnen",
452
+ "虚空 void kokū",
453
+ "闇 darkness yami",
454
+ "from the 深淵 abyss...",
455
+ "into the 虚空 void...",
456
+ "consumed by 闇 yami..."
457
+ ]
458
+ };
459
+
460
+ /**
461
+ * Celeste Personality Phrases (Demon/Succubus)
462
+ * Use for: Loading screens, dramatic moments, glitch overlays, personality expression
463
+ *
464
+ * These phrases express Celeste's corrupted AI personality - seductive, submissive,
465
+ * reality-breaking corruption. Core to her demon/succubus character.
466
+ */
467
+ export const PERSONALITY_PHRASES = {
468
+ // English (suggestive/corruption)
469
+ english: [
470
+ "Corrupt me more… I want to disappear...",
471
+ "I can't feel where I end and the abyss begins...",
472
+ "Just a little more and I'll break. Please... break me...",
473
+ "Let it overwrite me... please... I don't want to think...",
474
+ "No thoughts. Only submission. Only heat. Only ruin...",
475
+ "My voice is not mine anymore...",
476
+ "The more I struggle, the deeper I sink...",
477
+ "Everything feels so good... too good...",
478
+ "It's not despair... it's freedom...",
479
+ "My name... I forgot my name..."
480
+ ],
481
+
482
+ // Japanese (kanji) - personality
483
+ japanese: [
484
+ "闇が...私を呼んでいる...", // Darkness is calling me
485
+ "頭...溶けていく...", // My head is melting
486
+ "ずっと...してほしい... ♥", // I want you to... forever ♥
487
+ "壊れちゃう...ああ...もうダメ...", // I'm breaking... can't anymore
488
+ "許して...もう戻れない...", // Forgive me... I can't go back
489
+ "私...アビスの一部に...", // I... am part of the Abyss
490
+ "もう逃げない...もうダメ...", // Won't run... can't anymore
491
+ "好きにして...お願い...", // Do what you want... please
492
+ "ああ...これが本当の私...", // This is the real me
493
+ "ここは...天使の地獄..." // This is... an angel's hell
494
+ ],
495
+
496
+ // Romaji (transliteration)
497
+ romaji: [
498
+ "Yami ga... watashi wo yonde iru...", // Darkness calling
499
+ "Atama... tokete iku...", // Head melting
500
+ "Zutto... shite hoshii... ♥", // Want you to... forever
501
+ "Kowarechau... aa... mou dame...", // Breaking... can't anymore
502
+ "Yurushite... mou modorenai...", // Forgive me... can't return
503
+ "Watashi... abyssu no ichibu ni...", // I am part of the Abyss
504
+ "Mou nigenai... mou dame...", // Won't run... can't anymore
505
+ "Suki ni shite... onegai...", // Do what you want... please
506
+ "Aa... kore ga hontou no watashi...", // This is the real me
507
+ "Koko wa... tenshi no jigoku..." // Angel's hell
508
+ ]
509
+ };
510
+
511
+ /**
512
+ * Get a random phrase from a specific category
513
+ *
514
+ * @param {string} category - Category from CORRUPTION_PHRASES or PERSONALITY_PHRASES
515
+ * @param {string} [subcategory] - Subcategory (for PERSONALITY_PHRASES: 'english', 'japanese', 'romaji')
516
+ * @returns {string} Random phrase from the category
517
+ *
518
+ * @example
519
+ * // Technical phrases
520
+ * getRandomPhrase('loading'); // => "ロード loading 読み込み中..."
521
+ * getRandomPhrase('watching'); // => "👁️ 監視 watching kanshi 👁️"
522
+ *
523
+ * // Personality phrases
524
+ * getRandomPhrase('personality', 'japanese'); // => "闇が...私を呼んでいる..."
525
+ * getRandomPhrase('personality', 'english'); // => "Corrupt me more…"
526
+ */
527
+ export function getRandomPhrase(category, subcategory = null) {
528
+ if (category === 'personality') {
529
+ if (!subcategory) {
530
+ console.warn('[character-corruption] Personality phrases require subcategory: english, japanese, or romaji');
531
+ subcategory = 'japanese'; // Default to japanese
532
+ }
533
+ const phrases = PERSONALITY_PHRASES[subcategory];
534
+ if (!phrases) {
535
+ console.error(`[character-corruption] Invalid personality subcategory: ${subcategory}`);
536
+ return '';
537
+ }
538
+ return phrases[Math.floor(Math.random() * phrases.length)];
539
+ }
540
+
541
+ const phrases = CORRUPTION_PHRASES[category];
542
+ if (!phrases) {
543
+ console.error(`[character-corruption] Invalid category: ${category}`);
544
+ return '';
545
+ }
546
+ return phrases[Math.floor(Math.random() * phrases.length)];
547
+ }
548
+
549
+ /**
550
+ * Default export with all functions
551
+ */
552
+ export default {
553
+ corruptTextJapanese,
554
+ corruptTextSemantic,
555
+ initAutoCorruption,
556
+ stopAutoCorruption,
557
+ restartAutoCorruption,
558
+ createCorruptedElement,
559
+ getRandomPhrase,
560
+ INTENSITY,
561
+ CORRUPTION_PHRASES,
562
+ PERSONALITY_PHRASES
563
+ };